5

Trying to test a method which takes a list of objects and returns a sorted list of objects. Sorting happens on the basis of putting the first element on the list with empty string value. The test fails with the following error:

java.lang.AssertionError: 
Unexpected method call LoggerConfig.getName():
LoggerConfig.getName(): expected: 1, actual: 2

The issue here is Expecting an Explicit Number of Calls. Here it seems the method is called too often, which throws an exception that the method has been called too many times. The failure occurs immediately at the first method call exceeding the limit(taken from EasyMock guide). Question is how to fix it in this context? Where am I doing it wrong?

EasyMock code:

public class SorterTest {
private Sorter tested;
LoggerConfig item1;
LoggerConfig item2;
LoggerConfig item3;
List<LoggerConfig> sortedList;

@Before
public void setUp() {
    tested = new Sorter();
}

private List<LoggerConfig> makeUnsortedList() {
    item1 = EasyMock.mock(LoggerConfig.class);
    item2 = EasyMock.mock(LoggerConfig.class);
    item3 = EasyMock.mock(LoggerConfig.class);

    EasyMock.expect(item1.getName()).andReturn("com.core");
    EasyMock.expect(item2.getName()).andReturn("");
    EasyMock.expect(item3.getName()).andReturn("com.core.FOO");

    List<LoggerConfig> unsortedList = new ArrayList<>();
    unsortedList.add(item1);
    unsortedList.add(item2);
    unsortedList.add(item3);


    return unsortedList;
}

@Test
public void testSort() {

    List<LoggerConfig> unsortedList = makeUnsortedList();
    EasyMock.replay(item1,item2,item3);

    List<LoggerConfig> sortedList = tested.sort(unsortedList);

    assertTrue(sortedList.get(0).getName().isEmpty());
    assertTrue(sortedList.get(1).equals("com.core") || sortedList.get(1).equals("com.fwk.core.EBCTestClass"));
    assertTrue(sortedList.get(2).equals("com.core") || sortedList.get(2).equals("com.core.FOO"));

}

}

Testing the following method:

class Sorter {

  List<LoggerConfig> sort(List<LoggerConfig> unSortedList) {

    List<LoggerConfig> sortedList = new ArrayList<>(unSortedList);

    Collections.sort(sortedList, new Comparator<LoggerConfig>() {
        @Override
        public int compare(LoggerConfig o1, LoggerConfig o2) {
            return (o1.getName().compareTo(o2.getName()));
        }
    });

    return sortedList;
  }
}  
Yosef Weiner
  • 5,432
  • 1
  • 24
  • 37
PineCone
  • 2,193
  • 12
  • 37
  • 78

2 Answers2

15

It's calling getName() as part of the sort (possibly multiple times depending on the algorithm) and then again in your verification. Since you're not really interested in how many times it's called (as it's not part of your tested contract), remove the default restriction. To do that, replace andReturn with andStubReturn:

EasyMock.expect(item1.getName()).andStubReturn("com.core");
EasyMock.expect(item2.getName()).andStubReturn("");
EasyMock.expect(item3.getName()).andStubReturn("com.core.FOO");
Yosef Weiner
  • 5,432
  • 1
  • 24
  • 37
  • None of the suggestion allowed the test to pass. niceMock option gives `Nullpointer` exception. `andStubReturn` gives error for the first assertion `assertTrue(sortedList.get(0).getName().isEmpty());`. This line fails meaning problem here or in the actual implementation? – PineCone May 11 '17 at 08:22
  • This has fixed the issue along with a little change in the unit test. `assertTrue(sortedList.get(1).equals("com.core")` was missing the method call `getName()` and was passing the object only which couldn't compare. The fix is `assertTrue( sortedList.get(1).getName().equals("com.core")` – PineCone May 11 '17 at 08:50
  • 1
    @shaz I stand corrected; nice mocks are not the answer here as you noticed. You need to stub the methods so every call returns the expected value and does not revert to the "nice" (null-return) behavior after the expected number of calls (1). – Yosef Weiner May 11 '17 at 08:51
0

andStubReturn is indeed the way to go when you don't know (and don't care) how many times a method will be called.

I wanted to add that I found your assertions a bit strange. You know the exact outcome from the sort. Also, it is not recommended to call methods on a mock in the assertion part. Instead, you could do:

assertSame(item2, sortedList.get(0));
assertSame(item1, sortedList.get(1));
assertSame(item3, sortedList.get(2));
Henri
  • 5,551
  • 1
  • 22
  • 29