Search code examples
javaunit-testingjunitmockitojunitparams

How to use Mockito stubs in a JUnitParams parameter provider?


I am trying to learn JUnit. Working on a particular problem I decided to use JUnitParams parameter providers. Each set of parameters for a test method I'm writing should contain two input values and a list against which results of a method call would be tested:

private static final Object[] getConstraints() {
    return new Object[]{
            new Object[]{15, Equipment.WHITEBOARD, Arrays.asList(new Classroom[]{classroomA, classroomB})},
            new Object[]{15, Equipment.PROJECTOR, Arrays.asList(new Classroom[]{classroomB})},
            new Object[]{15, Equipment.MICROPHONE, Arrays.asList(new Classroom[]{classroomA})},
            new Object[]{30, Equipment.WHITEBOARD, Arrays.asList(new Classroom[]{classroomB})},
            new Object[]{30, Equipment.PROJECTOR, Arrays.asList(new Classroom[]{classroomB})},
            new Object[]{30, Equipment.MICROPHONE, Arrays.asList(new Classroom[]{})},
            new Object[]{45, Equipment.WHITEBOARD, Arrays.asList(new Classroom[]{})},
            new Object[]{45, Equipment.PROJECTOR, Arrays.asList(new Classroom[]{})},
            new Object[]{45, Equipment.MICROPHONE, Arrays.asList(new Classroom[]{})},
    };
}

classroomA and classroomB are actually Mockito stubs prepared before each test execution:

@Before
public void setUp() {
    classroomA = mock(Classroom.class);
    classroomB = mock(Classroom.class);
    classrooms = Arrays.asList(new Classroom[]{classroomA, classroomB});

    when(classroomA.getName()).thenReturn("A");
    when(classroomA.getCapacity()).thenReturn(20);
    when(classroomA.getEquipment()).thenReturn(Arrays.asList(new Equipment[]{Equipment.WHITEBOARD, Equipment.MICROPHONE}));

    when(classroomB.getName()).thenReturn("B");
    when(classroomB.getCapacity()).thenReturn(40);
    when(classroomB.getEquipment()).thenReturn(Arrays.asList(new Equipment[]{Equipment.WHITEBOARD, Equipment.PROJECTOR}));

    bookingSystem = new BookingSystem(classrooms);
}

The problem occurs when I try to use aforementioned lists of Classroom objects:

@Test
@Parameters(method = "getConstraints")
public void shouldBookClassroomMeetingConstraints(int capacity, Equipment equipment, List<Classroom>
        suitableClassrooms) {
    Assert.assertTrue("Should book a classroom that has a minimum capacity of " + capacity + " and has " +
            equipment,
            suitableClassrooms.contains(bookingSystem.book(capacity, equipment, ANY_DAY_OF_WEEK, ANY_HOUR)));
}

Debugging shows that during the first run suitableClassrooms contains 2 objects, but further inspection shows that all elements are null - the stubs I prepared are not there. Obviously, the tests don't pass or fail where they should pass or fail.

Is there a limitation on using JUnitParams with Mockito or am I using them wrong? What is the right way to use them?

It is also possible that this is a wrong technique of unit testing. If this is the case, what is the proper way of writing a test that verifies if the result of a method call is in a given array?


Solution

  • You test doesn't work because JUnitParamsRunner runner collects parameters for test (i.e. invokes getConstraints method) before invocation of @Before methods and even before @BeforeClass. So classroomA and classroomB are null at that moment. That is why suitableClassrooms consists of null elements.
    The solution is to initialize classroomA and classroomB in the getConstraints() method.

    Also I believe you can get rid of mockito here. Classroom looks like POJO and it's not necessary to mock POJOs. In such case you just need to create Classroom instance and fill it with necessary data.