Consider the following class and test:
public class Sample {
Object constructorAttribute;
Object propertyAttribute;
Object fieldAttribute;
public Sample(Object constructorAttribute) {
this.constructorAttribute = constructorAttribute;
}
public void setPropertyAttribute(Object propertyAttribute) {
this.propertyAttribute = propertyAttribute;
}
}
@RunWith(MockitoJUnitRunner.class)
public class SampleTest {
@Mock
Object fieldAttribute;
@Mock
Object constructorAttribute;
@Mock
Object propertyAttribute;
@InjectMocks
// @Spy
Sample injectionSample;
@Test
public void constructor() {
assertEquals(constructorAttribute, injectionSample.constructorAttribute);
}
@Test
public void setter() {
// verify(injectionSample).setPropertyAttribute(propertyAttribute);
assertEquals(propertyAttribute, injectionSample.propertyAttribute);
}
@Test
public void field() {
assertEquals(fieldAttribute, injectionSample.fieldAttribute);
}
}
This is a standard use case for @InjectMocks. As stated in
http://docs.mockito.googlecode.com/hg/1.9.5/org/mockito/InjectMocks.html only
the
constuctor injection is used. In the object injectionSample, the
propertyAttribute and fieldAttribute are null while the constructorAttribute
receives a mock.
The setter test and the field test fail as expected. There is a problem with
the constructor test which can fail because the parameter resolution is made by
type. Since all the mocks have the same type, Object in this case, mockito
takes one of them and use it in constructor injection. It makes the constructor
test depend on the order in which mocks and attributes are defined.
Now please consider the following test:
@RunWith(MockitoJUnitRunner.class)
public class SuperSampleTest extends BaseTest {
@Mock
Object constructorAttribute;
@InjectMocks
Sample injectionSample;
@Test
public void constructor() {
assertEquals(constructorAttribute, injectionSample.constructorAttribute);
}
@Test
public void setter() {
assertEquals(propertyAttribute, injectionSample.propertyAttribute);
}
@Test
public void field() {
assertEquals(fieldAttribute, injectionSample.fieldAttribute);
}
}
public class BaseTest {
@Mock
Object propertyAttribute;
@Mock
Object fieldAttribute;
}
It does the same tests as in the first case with the difference that some mocks
are declared in a base test class. The surprise is that all the tests pass. All
the attributes of the object injectionSample are mocked. In this case Mockito
does all the injections: the constructor, the property and the field injection.
It is inconsistent with the docs and the first test case.
Another issue with the documentation is the description of how the injection
algorithm works. Only one of the three injection types should happen when
@InjectMocks annotation is used. It lacks an explanation of why. In practice,
when the annotation is used for setter and/or field injection it seems to make
no exclusion between this two types of injection. Both of them are applied.
Some clarification would help.
The tests are done with mockito 1.9.5 on win 7 64 bit, jdk 1.7.0-13 64 bit.
Let me know if I can be of any further help.
Original issue reported on code.google.com by lpet...@gmail.com on 27 Sep 2013 at 3:17
Original issue reported on code.google.com by
lpet...@gmail.com
on 27 Sep 2013 at 3:17Attachments: