One of the tested methods produced a sorted list of values. Sorting was an essential part of the business logic. Here is a quick draft of how the implementation looked like:
class Foo {
public List<String> getTheList() {..}
}
class Bar {
private Foo foo = new Foo();
public List<String> doSomethingClever() {
List<String> theList = foo.getTheList();
..
// do something clever
..
// finally, return the sorted results
Collections.sort(theList)
return theList;
}
}
With simplicity in mind I didn't bother with looping over the list to see if the records were sorted as expected. Instead, I merely wanted to check that the list was passed as an argument to the static call of Collections.sort. Using PowerMock it only takes a few lines of code to accomplish this task: ..
import static org.mockito.Mockito.when;
import static org.powermock.api.mockito.PowerMockito.doNothing;
import static org.powermock.api.mockito.PowerMockito.spy;
import static org.powermock.api.mockito.PowerMockito.verifyStatic;
..
@Test
public void recordsShouldBeSorted() {
// the list I expect to be sorted later on
final List expectedList = new Foo().getTheList();
// letting PowerMock in
spy(Collections.class);
doNothing().when(Collections.class);
// confusing as it is, no sorting happens at this stage
Collections.sort(expectedList)
// cool, now I am ready to check the list got sorted
// without looking at the returned data
// let's invoke the tested method
new Bar().doSomethingClever();
// time to verify the sorting was applied
verifyStatic();
// once again a bit confusing
// this time it checks the expected list
// was passed as an argument to the sort call
Collections.sort(expectedList);
}
Hope it makes sense. If not, here is the pattern from the framework's point of view: - Tell me which class and which static method
- Call the business method invoking the static method we agreed on
- Let me check if the static method got called with expected arguments
Personally, I consider this a cool feature. Of course, all that magic doesn't come completely for free and some extra arrangements are needed:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest({Collections.class, Bar.class})
public void BarTest {
@Test
public void recordsShouldBeSorted() {..}
That's it. Originally, I overlooked the need to add the tested class (Bar in this example) to the PrepareForTest annotation. I was pulling my hair out when trying to understand why the heck the test wouldn't pass even though debugging proved the sorting did happen. It took me way too long to spot that tiny but substantial mistake. I hope this post helps someone else to save a bit of their time.
No comments:
Post a Comment