Reputation: 92549
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?
Upvotes: 0
Views: 6681
Reputation: 16390
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.
Upvotes: 5
Reputation: 121820
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).
Upvotes: 1
Reputation: 328825
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());
Upvotes: 1