Question

I want to test, whether Collection.sort(...) is called or not with JMockit:

final List<Employee> employees = new ArrayList<>();
new Expectations() {
  {
    Collections.sort((List<Employee>) any);
    result = employees;
  }
};

assertThat(EmployeeRepository.getAllOrderedByName()).isSameAs(employees);

This is the implementation of my example repository under test:

public class EmployeeRepository {

  private static List<Employee> employees = new ArrayList<>();

  public static List<Employee> getAllOrderedByName() {
    Collections.sort(employees);
    return employees;
  }
}

When I run the unit test I get a NullPointerException at Collections.sort. It seems like it is a problem in the mocking it self since the debugger never reaches a break point in the getAllOrderedByName method.

How can I stub static methods using any with JMockit?

Was it helpful?

Solution

In your test code, the Collections class is never specified to be mocked. Therefore, that Collections.sort((List<Employee>) any); call throws an NPE because the value of any is null and the actual sort method is executed.

You probably assumed that any method call inside an expectation block would be automatically mocked, but that's not how the JMockit API works. Instead, you need to explicitly specify which types are mocked, by declaring a mock field or a mock parameter annotated with @Mocked, @NonStrict, @Cascading, or @Capturing.

Also, in this case Collections.sort is a method that returns void, so it doesn't make sense to record a return value for it.

Furthermore, writing the test like this is not what I would recommend anyway. It should instead verify that the resulting collection is sorted, without ever mocking the Collections class.

OTHER TIPS

That does not answer your specific question (and I have had difficulties with any myself in the past so I try to avoid it!), but you could use a MockUp instead:

final AtomicBoolean wasCalled = new AtomicBoolean();

new MockUp<Collections> () {
    @Mock
    public <T extends Comparable<? super T>> void sort(List<T> list) {
        wasCalled.set(true);
        //no-op otherwise
    }
};

assertThat(EmployeeRepository.getAllOrderedByName()).isSameAs(employees);
assertTrue(wasCalled.get());

I wouldn't do it this way if I were you.

First, test that your Comparable on Employee works.

Then create mocks of your Employee class. Note: using mockito here, but I guess this can be adapted to jmockit (which I have never used):

private static final int NR_MOCKS = 20;

// ....

List<Employee> sorted = new ArrayList<>(NR_MOCKS);
for (int i = 0; i < NR_MOCKS; i++)
    sorted.add(mock(Employee.class));

// Create a shuffled list of the sorted list
List<Employee> shuffled = new ArrayList<>(sorted);
Collections.shuffe(shuffled);

// Inject shuffled into repository

// Stubs
for (int i1 = 0; i1 < NR_MOCKS; i1++)
    for (int i2 = 0; i2 < NR_MOCKS; i2++)
        when(sorted.get(i1).compareTo(sorted.get(i2))).thenReturn(i2 - i1);

List<Employee> actual = EmployeeRepository.getAllOrderedByName();

assertEquals(actual, sorted);

Not only does it check that the list is eventually sorted (since you have already tested your Comparable implementation beforehand), but you don't care what sorting algorithm is used; it Just Works(tm).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top