Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Mockito @InjectMocks work?

Here's my question:

I have several web services classes to test that all inherit their methods from a generic service. Rather than write a unit test for each, I figure I can break the test suite down by functional areas (i.e. three groups of test methods, each relying on a different underlying DAO method call).

What I propose to do is:

@Mock StateDAO mockedStateDao;
@Mock CountyDAO mockedCountyDao;
@Mock VisitorDAO mockedVisitorDao;

then call:

@InjectMocks CountyServiceImpl<County> countyService = new CountyServiceImpl<County>();
@InjectMocks StateServiceImpl<State> stateService = new StateServiceImpl<State>();
@InjectMocks VisitorServiceImpl<Visitor> visitorService = new VisitorServiceImpl<Visitor>();

How can I be sure that each mockedDAO will be injected into the correct service? Would it be easier to autowire all three (rather than use @InjectMocks)?

I'm using Spring, Hibernate, and Mockito...

like image 888
DYezek Avatar asked Mar 05 '13 16:03

DYezek


People also ask

What is the difference between @InjectMocks and mock?

@InjectMocks creates an instance of the class and injects the mocks that are created with the @Mock annotations into this instance. @Mock is used to create mocks that are needed to support the testing of the class to be tested. @InjectMocks is used to create class instances that need to be tested in the test class.

What does @mock annotation do?

@Mock: It is used to mock the objects that helps in minimizing the repetitive mock objects. It makes the test code and verification error easier to read as parameter names (field names) are used to identify the mocks. The @Mock annotation is available in the org. mockito package.

Does InjectMocks inject spy?

The same stands for setters or fields, they can be declared with private visibility, Mockito will see them through reflection. However fields that are static or final will be ignored. Again, note that @InjectMocks will only inject mocks/spies created using the @Spy or @Mock annotation.

How do you mock an injected object?

Mockito @InjectMocks annotations allow us to inject mocked dependencies in the annotated class mocked object. This is useful when we have external dependencies in the class we want to mock. We can specify the mock objects to be injected using @Mock or @Spy annotations.


1 Answers

Well nicholas answer is almost correct, but instead of guessing just look at the javadoc of InjectMocks, it contains more details ;)

To me it's weird to have so many Service in a single test, it doesn't feel right, as a unit test or as an integration test. In unit test it's wrong because well you have way too much collaborators, it doesn't look like object oriented (or SOLID). In integration tests, it's weird because the code you test the integration with the DB not mock it.

For a rapid reference in 1.9.5 you have :

Mark a field on which injection should be performed.

Allows shorthand mock and spy injection. Minimizes repetitive mock and spy injection. Mockito will try to inject mocks only either by constructor injection, setter injection, or property injection in order and as described below. If any of the following strategy fail, then Mockito won't report failure; i.e. you will have to provide dependencies yourself.

  1. Constructor injection; the biggest constructor is chosen, then arguments are resolved with mocks declared in the test only.

    Note: If arguments can not be found, then null is passed. If non-mockable types are wanted, then constructor injection won't happen. In these cases, you will have to satisfy dependencies yourself.

  2. Property setter injection; mocks will first be resolved by type, then, if there is several property of the same type, by the match of the property name and the mock name.

    Note 1: If you have properties with the same type (or same erasure), it's better to name all @Mock annotated fields with the matching properties, otherwise Mockito might get confused and injection won't happen.

    Note 2: If @InjectMocks instance wasn't initialized before and have a no-arg constructor, then it will be initialized with this constructor.

  3. Field injection; mocks will first be resolved by type, then, if there is several property of the same type, by the match of the field name and the mock name.

    Note 1: If you have fields with the same type (or same erasure), it's better to name all @Mock annotated fields with the matching fields, otherwise Mockito might get confused and injection won't happen.

    Note 2: If @InjectMocks instance wasn't initialized before and have a no-arg constructor, then it will be initialized with this constructor.

like image 113
Brice Avatar answered Oct 05 '22 10:10

Brice