0

I'm trying to test a spring rest controller class using JUnit, Mockito, Spring test and Spring Security test. The following is my rest controller class for which i'm performing the test;

@RestController
public class EmployeeRestController {

    @Autowired
    private EmployeeService employeeService;

    @PreAuthorize("hasAnyRole('ROLE_EMPSUPEADM')")
    @RequestMapping(value = "/fetch-timezones", method = RequestMethod.GET)
    public ResponseEntity<List<ResponseModel>> fetchTimeZones() {
        List<ResponseModel> timezones = employeeService.fetchTimeZones();
        return new ResponseEntity<>(timezones, HttpStatus.OK);
    }

}

The following is my test class;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfiguration.class})
@WebAppConfiguration
public class EmployeeRestControllerUnitTest {

private MockMvc mockMvc;

@Autowired
private WebApplicationContext webApplicationContext;

@Mock
private EmployeeService employeeService;

@InjectMocks
private EmployeeRestController employeeRestController;

@Before
public void init() {
    MockitoAnnotations.initMocks(this);
    Mockito.reset(employeeService);
    mockMvc = MockMvcBuilders
                .webAppContextSetup(webApplicationContext)
                .build();
}

@Test
@WithMockUser(roles = {"EMPSUPEADM"})
public void testFetchTimezones() {
    try {
        mockMvc.perform(get("/fetch-timezones"))
          .andExpect(status().isOk())               
          .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
          .andExpect(jsonPath("$", hasSize(4)));
        verify(emploeeService, times(1)).fetchTimeZones();
        verifyNoMoreInteractions(employeeService);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

}

I made the above test class by refering many tutorials. The problem is i'm not able to understand everything clearly. so, i'm having the following doubts.

  1. I'm creating a mock of EmployeeService and injecting it into EmployeeRestController using @InjectMocks, then why i'm getting the following failure;

    Wanted but not invoked:
    careGroupService.fetchTimeZones();
    -> at com.example.api.test 
    .restcontroller.EmployeeRestControllerUnitTest 
    .testFetchTimezones(EmployeeRestControllerUnitTest.java:73)
    Actually, there were zero interactions with this mock.
    
  2. How does MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); works exactly.

  3. I know that MockMvcBuilders.standaloneSetup(employeeRestController) is for testing individual controller classes and spring configuration will not be available for this method. How can we provide spring configuraton for this method, is it possible.

  4. Finally, how does this piece of code: Mockito.reset(employeeService); works.

karthi
  • 549
  • 3
  • 15
  • 26

1 Answers1

2

1) you do verify for

verify(emploeeService, times(1)).fetchTimeZones();

but you didn't setup mock behaviour for it (before you call mockMvc.perform(get("/fetch-timezones"))).

List<ResponseModel> timezones = new ArrayList<>();
when(emploeeService.fetchTimeZones()).thenReturn(timezones );

2) create MockMvc from context. mockmvc emulates web container, use mock for all where is possible but supports http call and gave the possibility to call controller.

It stands up the Dispatcher Servlet and all required MVC components, allowing us to test an endpoint in a proper web environment, but without the overhead of running a server.

3) when you use:

@MockBean private EmployeeService employeeService;

you override real service. remove it from test class real service will be used in testing. Instead of use @Mock use @MockBean. @MockBean it's override by container, with @Mock you need to inject this into controller by reflection

or without spring boot with reflection:

@Before
public void init() {
    MockitoAnnotations.initMocks(this);
    Mockito.reset(employeeService);
    mockMvc = MockMvcBuilders
                .webAppContextSetup(webApplicationContext)
                .build();
    EmployeeRestController employeeRestController=  
            webAppContext.getBean(EmployeeRestController.class);
    ReflectionTestUtils.setField(employeeRestController, 
                                 "employeeService",
                                 employeeService);
}

4) Mockito.reset(employeeService);- you reset all behaviors that you setupped before. Mock contains information from when(), verify() and controls it , call reset - it's clean all information.

xyz
  • 5,228
  • 2
  • 26
  • 35
  • Hi, thanks for your answers. But I'm still getting the same failure message. – karthi Jul 18 '17 at 04:30
  • Sorry, I'm not using spring boot. – karthi Jul 18 '17 at 04:51
  • Thanks for your help, I was able to achieve it by providing a **test context** as suggested in this [Link](https://stackoverflow.com/questions/37369768/should-mockito-be-used-with-mockmvcs-webappcontextsetup-in-spring-4) – karthi Jul 18 '17 at 10:40