From this Difference between @Mock and @InjectMocks I understand that @InjectMocks is used as an annotation for
create an instance and inject the mocks that are created with @Mock into it.
I don't think I understand how it works.
I have an example code on which I would like to ask you 2 questions in order to go straight to the points that are not clear to me.
The questions are at the end.
I have an interface:
public interface SimpleAgenda {
public List<String> getAppointments();
public String getAppointment(Date d);
public void addAppointments(Date d, String label);
}
And a class that implements this interface:
public class MyAgenda implements SimpleAgenda {
private Map<String, String> appointments;
@Override
public List<String> getAppointments() {
List<String> lst = new ArrayList<String>();
System.out.println(this.appointments == null);
for (String key : this.appointments.keySet()) {
String label = this.appointments.get(key);
lst.add(label);
}
return lst;
}
@Override
public String getAppointment(Date d) {
String dateString = d.toString();
String app = this.appointments.get(dateString);
return app;
}
@Override
public void addAppointments(Date d, String label) {
// TODO Auto-generated method stub
// this behavior is not implemented yet in this class
}
}
And finally I have the test class:
// @RunWith attaches a runner with the test class to initialize the test data
@RunWith(MockitoJUnitRunner.class)
public class AgendaTest {
private static final String LABEL = "This is a mock appointment for: ";
// @InjectMocks annotation is used to create and inject the mock object
@InjectMocks
MyAgenda agenda = new MyAgenda();
// @Mock annotation is used to create the mock object to be injected
@Mock
Map<String, String> mockedAppointments;
@Before
public void createMocks() {
Date d1 = (new GregorianCalendar(120, 4, 15)).getTime();
Date d2 = (new GregorianCalendar(119, 7, 31)).getTime();
String key;
key = d1.toString();
// add the mocked behavior of for a set of given dates
when(mockedAppointments.get(key)).thenReturn(LABEL + key);
key = d2.toString();
// 1. add the mocked behavior of for a set of given dates.
// 2. Strict stubbing that requires that all declared stubs are actually used
// the statement lenient() relax this requirement. Check the manual.
lenient().when(mockedAppointments.get(key)).thenReturn(LABEL + key);
when(mockedAppointments.size()).thenReturn(2);
}
@Test
public void mockTest() {
for (String key : mockedAppointments.keySet()) {
String v = mockedAppointments.get(key);
// Do not worry, we will never reach this line. We are querying the object on
// method that was not mocked (i.e. keySet).
Assert.fail();
}
int size = mockedAppointments.size();
Assert.assertEquals(2, size);
}
@Test
public void simpleTest() {
int appCounter = agenda.getAppointments().size();
// Do not expect that appCounter is 2 (or more in general different than 0) ...
// we are actually querying an object that was not mocked!!!
// See the details of the implementation of the method: MyAgenda.getAppointments()
Assert.assertEquals(0, appCounter);
}
These are my questions:
- In
mockTest()
when i call mockedAppointments.keySet()
it return an empty set... my question is: why mockedAppointments.keySet()
doesn't throw a nullPointerException
(mockedAppointments is only declared)? maybe because it's a mock? And if the reason is this, why doesn't a mock throw "nullPointerException"?
- In
simpleTest()
we have agenda.getAppointments().size();
; agenda.getAppointments()
contains System.out.println(this.appointments == null);
and this line prints "false" is i keep the @InjectMocks annotation, "true" otherwise, but why? In the first case (@InjectMocks is kept) where is the "appointments" attribute of "agenda" initialized? Is it initialized because we inject the value of mockedAppointments
into it? If yes, does Mockito only do this based on the type of the mock defined in the test class and the type of the attribute defined in MyAgenda
?
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…