Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
220 views
in Technique[技术] by (71.8m points)

java - Mockito how does @InjectMocks works

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:

  1. 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"?
  2. 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?

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
  1. Qn 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"?
    Answer is : Because mockedAppointments.keySet().size is 0 and mockedAppointments.keySet() is empty, it is the behavior of the mock
  2. 2.0 Qn System.out.println(this.appointments == null); line prints "false" is i keep the @InjectMocks annotation, "true" otherwise, but why?
    Answer is : In junit or mockito System.out.println won't works, rather use logger.
    2.1 Qn In the first case (@InjectMocks is kept) where is the "appointments" attribute of "agenda" initialized?
    Answer is : it is mocking the class and eg for list it initialize as 0 and keep value as empty, Inaddition to that
@InjectMocks
private MyAgenda agenda;

should be declared like this
2.2 Qn Is it initialized because we inject the value of mockedAppointments into it?
Answer is : mockedAppointments and agenda doesn't have any connection, inaddition to that Rather this injectMocks you can use @Mocks,it works.

 @Mocks
 private MyAgenda agenda; 

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...