1

I have a question about bean creation in testing of controllers. For example, there is a such test

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {MainApplicationConfiguration.class, JPAConfig.class})
@WebAppConfiguration
public class TestMainController {

    private MockMvc mockMvc;
    @Before
    public void setUp() {
    MockitoAnnotations.initMocks(this);
    mockMvc = MockMvcBuilders.standaloneSetup(mainController).build();
    }
    @InjectMocks
    private MainController mainController;

    @Mock
    private EntryService entryService;

    @Autowired
    DBEntryRepository repository;

    @Test
    public void testEntryGet() throws Exception {

        List<DBEntry> response_data = new ArrayList<>();
        response_data.add(new DBEntry(1, 1, "STR", "DATE"));

        Mockito.when(entryService.findAllEntries())
                .thenReturn(response_data);
        MvcResult result = mockMvc.perform(get("/VT/entry/"))
                .andExpect(status().isOk()).andReturn();
        verify(entryService, times(1)).findAllEntries();
        verifyNoMoreInteractions(entryService);
    }
}

and a controller method mapped on

/VT/entry/

@RequestMapping(value = "/entry/", method = RequestMethod.POST)
    public ResponseEntity<Void> createEntry(@RequestBody DBEntry entry, UriComponentsBuilder ucBuilder) {
        System.out.println("Creating entry " + entry.getNum());
        try {
            entryService.saveEntry(entry);
            entryService.refreshEntryService();
        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseEntity<Void>(HttpStatus.BAD_REQUEST);
        }
        HttpHeaders headers = new HttpHeaders();
        headers.setLocation(ucBuilder.path("/entry/{id}").buildAndExpand(entry.getId()).toUri());
        return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
    }

EntryService is annotated with @Service annotation and MainApplicationConfiguration.class is a configuration with @EnableWebMvc and scan project for this EntryService.

by that I want to show that this controller really uses this EntryService in a real application and all are coupled by MainApplicationConfiguration.class.

Question is: Why entryService with @Mock annotation ended up in my controller code in the scope of my test execution? Shouldn't it be only for that instance only and inside of controller should be instantiated another bean(EntryService), why this annotation has mocked all occurrences of that bean (in the test scope)? I was thinking, that I should write whole other context web-context instead of MainApplicationConfiguration.class to mock it inside and substitute current definition. I am absolutely confused why this simple annotation have made such thing.

And if somebody can understand this magic, please say what is difference between @InjectMock and @Mock?

thanks for your attention! and sorry if my question is quite stupid. I am very new, it works, but I have not got magic yet.

Alex
  • 3,923
  • 3
  • 25
  • 43

1 Answers1

2

In the documentation for @InjectMocks:

Mockito will try to inject mocks only either by constructor injection, setter injection, or property injection in order

So since EntryService is a dependency of your controller, @InjectMocks will try to find a mock object of EntryService in your test class and inject it into mainController.

Note that only one of constructor injection, setter injection, or property injection will occur.

@Mock marks the fields as mock objects. @InjectMocks injects mock objects to the marked fields, but the marked fields are not mocks.

  • this is not answer on main part of the question. – Alex Dec 30 '17 at 20:40
  • @Alex The difference is included in my comment. You could see more in this [post](https://stackoverflow.com/questions/16467685/difference-between-mock-and-injectmocks). – Jenny Saqiurila Dec 30 '17 at 20:42
  • You know, you try to cite something, but this citation isn't answer on this question(: Thanks for your efforts! My EntryService is annotated with @Mock annotation. – Alex Dec 30 '17 at 20:48
  • @Alex Isn't your question "Why `entryService` with `@Mock` annotation ended up in my controller code in the scope of my test execution?"? It is in your controller because of the `@InjectMocks` annotation on your `mainController`. – Jenny Saqiurila Dec 30 '17 at 21:00