Is it possible to create a test repository for mockMVC? - spring

I have the test below:
#AutoConfigureMockMvc
#SpringBootTest
public class ProjectDashboardTests {
#Autowired
private MockMvc mockMvc;
#Test
public void projectsDashboardShows() throws Exception {
this.mockMvc
.perform(get("/projects/1"))
.andDo(print())
.andExpect(status().isOk());
}
#Test
public void projectFormShows() throws Exception {
this.mockMvc
.perform(get("/get-project-form/1"))
.andDo(print())
.andExpect(status().isOk());
}
These rely upon path variables 1 = user ID. For these tests to work correctly there must a user account with user id = 1 which is currently logged in. How would I simulate that in mockMVC?

You have few options, depends which test you want to create and which configuration you have (more detail is needed to answer more accurately).
For unit tests, you can mock your repository (or service), and method in which you get the Project. For example if you have ProjectService with method getProjectById(Long id), you can use something like that:
#AutoConfigureMockMvc
#SpringBootTest
public class ProjectDashboardTests {
...
#MockBean
private ProjectService service; // <- mock your service
#Test
public void projectsDashboardShows() throws Exception {
// mock service method in selected test or in #BeforeEach method
Mockito.when(service.getProjectById(ArgumentMatchers.anyLong())
.thenReturn(new Project(/* your own test object*/));
...
}
...
}
Based on For these tests to work correctly there must a user account with user id = 1 which is currently logged in, I assume you work with Spring Security? You can take a look at the #WithMockUser annotation if you want simulate selected user.
For integration tests, you should prepare database (H2 for example) for tests only, before each test add project into db and remove after each test (run independently).

Related

Is Injecting Repository dependency in Integration Testing is bad practice

I am developing REST CURD API using Spring Boot and following TDD. I am starting with READ operation to test the READ works I have to prepopulate data in my DB. For this purpose I am using H2 DB and created my Repository and using this Repository in my Integration testing Setup step to populate the data before my GET actual data being executed. My college told me its bad practice using Repository in integration testing to create data for this GET operation test instead he suggested to call POST API endpoint in Setup step and Execute GET test also implement PUT and DELETE IT tests.
My question is
Is injecting actual repository for purpose of data setup in Integration test class is wrong?
Can we use/call and Endpoint (POST) in setup or in GET testcase before actual Test logic being executed?
Can we call POST endpoint in init/setup and populate the data instead using Repository and implement GET,PUT,DELETE tests using POST data? Is advisable calling direct POST endpoint in setup for purpose of testing another endpoint in Test class and using #TestOrder annotation on class level.
Case 1
#SpringBootTest
#AutoConfigureMockMvc
public class CURDTest() {
#Autowired
private TestMovieRepository testMovieRepository;
#BeforeEach
void init() {
Movie myMovie = new Movie("test");
testMovieRepository.save(myMovie);
}
#Test
void getMovie_whenReturnsMovie(){
//Test logic using mockMvc;
}
}
Case 2:
#SpringBootTest
#AutoConfigureMockMvc
public class CURDTest() {
#BeforeEach
void init() {
//call POST Endpoint usin MockMvc populate data in table
}
#Test
void getMovie_whenReturnsMovie(){
//Test logic using mockMvc;
}
}
Case 3:
#SpringBootTest
#AutoConfigureMockMvc
#TestOrder
public class CURDTest() {
#BeforeEach
void init() {
//call POST Endpoint usin MockMvc populate data in table
}
#Test
#Order(1)
void getMovie_whenReturnsMovie(){
//Test logic using mockMvc;
}
#Test
#Order(2)
void updateMovie_whenReturnsMovie(){
//Test logic using mockMvc;
}
}

Mocking Repositories to test Service in Spring

I occurred some failures after trying to mock repositories to unit test my services in Spring-Boot
Thats what I have (simplified)
#ExtendWith(SpringExtension.class)
#ExtendWith(MockitoExtension.class)
#SpringBootTest
#ActiveProfiles("test")
public class UserTest{
#InjectMocks
private UserServiceImpl userService;
#Mock
private UserRepostiory userRepository;
#Before
public void setUp() {
User user = new User(1L, "email#email", "name");
when(userRepostitory.findById(1L)).thenReturn(Optional.of(user));
}
#Test
public void findUserByIdReturnsUser() {
User user = userService.getById(1L); => always throws error in Service, that no User is found with that Id, it calls the regular Repository: mock does nothing
assertEquals(1L,user.getId());
}
}
But I never get the User returned when the service calls the repo. I am kinda new to Unit Testing, and I am pretty sure, that I miss something here.
In the setUp you do:
when(userRepostitory.findById(1L)).thenReturn(Optional.of(user));
But in the Test you call
User user = userService.getById(1L);
Either mock getById or call findById
"Repostiory" | "Repostitory" looks like a typo error.
Annotate the test class with #RunWith(SpringRunner.class)

Testing Spring Data Rest

I want to test a Spring boot 2 respository as rest controller app.
App is working well from browser ( http://localhost:8080/api/v1/ehdata ), but I cannot find an example how can I test it with Spring test environment. Very important, there are no RestControllers and Services, only Repositories annotated like this:
#RepositoryRestResource(path = EhDataRepository.BASE_PATH,
collectionResourceRel = EhDataRepository.BASE_PATH)
public interface EhDataRepository extends
PagingAndSortingRepository<EhData, Long> {
public static final String BASE_PATH="ehdata";
}
I tried with this test, but responses was empty, and status code was 404:
#RunWith(SpringRunner.class)
#SpringBootTest
#WebMvcTest(EhDataRepository.class)
public class RestTest extends AbstractRestTest {
#Autowired MockMvc mvc;
#Test
public void testData() throws Exception {
mvc.perform(get("/api/v1/ehdata")
.accept(MediaTypes.HAL_JSON_VALUE))
.andDo(print())
.andExpect(status().isOk())
.andExpect(header().string(HttpHeaders.CONTENT_TYPE,
MediaTypes.HAL_JSON_VALUE+";charset=UTF-8")
.andReturn();
}
}
thx,
Zamek
You will need to mock the output from the respository like this based on the method you are trying to test:
#MockBean
private ProductRepo repo;
And then
Mockito.when(this.repo.findById("PR-123")
.get())
.thenReturn(this.product);
this.mvc.perform(MockMvcRequestBuilders.get("/products/{id}", "PR-123")
.contentType(MediaType.APPLICATION_JSON_VALUE))
.andReturn();
Also, remove the server-context-path while calling API in perform() method.

How do I verify that an event has been published using Spring, JUnit, and Mockito?

I'm using Spring 4.3.8.RELEASE with JUnit 4.12 and Mockito 1.10.18. I have a service that publishes events ...
#Service("organizationService")
#Transactional
public class OrganizationServiceImpl implements OrganizationService, ApplicationEventPublisherAware
publisher.publishEvent(new ZincOrganizationEvent(id));
#Override
public void setApplicationEventPublisher(ApplicationEventPublisher publisher)
{
this.publisher = publisher;
}
...
#Override
public void save(Organization organization)
{
...
publisher.publishEvent(new ThirdPartyEvent(organization.getId()));
My question is, how do I verify in a JUnit test that an event has actually been published?
#Test
public void testUpdate()
{
m_orgSvc.save(org);
// Want to verify event publishing here
I prefer the opposite approach, which is more integration test-ey:
🧙‍♂️Mock the ApplicationListener using Mockito
đź”—Register the mock application listener onto the ConfigurableApplicationContext
🔨Do work
✔Verify the mock has received the event
With this approach you are testing that an event has been published by means that someone is receiving it.
Here is the code of a rudimental authentication test. Among other conditions, I test that a login event has occurred
#Test
public void testX509Authentication() throws Exception
{
ApplicationListener<UserLoginEvent> loginListener = mock(ApplicationListener.class);
configurableApplicationContext.addApplicationListener(loginListener);
getMockMvc().perform(get("/").with(x509(getDemoCrt())))//
.andExpect(status().is3xxRedirection())//
.andExpect(redirectedUrlPattern("/secure/**"));
getErrorCollector().checkSucceeds(() -> {
verify(loginListener, atLeastOnce()).onApplicationEvent(any(UserLoginEvent.class));
return null;
});
}
My advice is to unleash the power of Mockito to deeply verify the event arguments. In my case, I will extend my code to:
Check that the username in the login event matches the authenticated principal
Perform additional tests where the user blatantly fails to login and I will expect one of the various login failure events
If you want to test if you didn't forget to call publishEvent method inside your OrganizationServiceImpl you can use something like this:
class OrganizationServiceImplTest {
private OrganizationServiceImpl organizationService;
private ApplicationEventPublisher eventPublisher;
#Before
public void setUp() {
eventPublisher = mock(ApplicationEventPublisher.class);
organizationService = new OrganizationServiceImpl();
organizationService.setApplicationEventPublisher(eventPublisher)
}
#Test
public void testSave() {
/* ... */
organizationService.save(organization);
verify(eventPublisher).publishEvent(any(ThirdPartyEvent.class));
}
}
Test case above will verify whether or not there was an invocation of publishEvent method.
For more check the documentation.
Regarding:
My question is, how do I verify in a JUnit test that an event has actually been published?
You have to test ApplicationEventPublisher implementation and probably without mocks if you want to verify actual sending.

Unit Testing of Spring MVC Controller: Failing to fully perform request

I have a simple controller defined as below:
#Controller
#RequestMapping("/rest/tests")
public class TestController {
#Autowired
private ITestService testService;
#RequestMapping(value="/{id}", method=RequestMethod.DELETE)
#ResponseStatus(value = HttpStatus.OK)
public void delete(#PathVariable Integer id)
{
Test test = testService.getById(id);
testService.delete(test);
}
}
I have been trying to test the delete method, and have not succeeded so far. The test I have written is pretty simple too.
public class MockmvcTest {
#InjectMocks
private TestController test;
private MockMvc mockMvc;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(test).build();
}
#Test
public void myTest() throws Exception {
this.mockMvc.perform(delete("/rest/tests/{id}", new Integer(4)))
.andExpect(status().isOk()
}
}
I have tested the method using "advanced rest client" extension in chrome and it works as expected.
By working I mean that the entity with the given id is deleted from database.
When myTest() is executed the status code is still 200, but the entity is not removed from the database.
What might be the reason behind this behavior?
You're using Mockito to inject mock service beans into your TestController (in particular, ITestService). All mocks by definition have no behaviour until you specify it, by default all operations you perform will either do nothing or return null. You can easily confirm that by setting a breakpoint inside TestController.delete method, executing the test in debug mode and inspecting values of test and testService variables.
Mockito is used for unit-level tests that replace SUT's collaborators with a mock that you set up to behave in a certain verifiable way. Once you call a method on your SUT (in your case that's TestController) you can assert whether it adheres to its contract or not.
It's actually a big no-no to allow your automated tests to modify a real instance of a database.

Resources