Panteleev Dima
Panteleev Dima

Reputation: 185

How can I unit test a method with multiple internal calls to class I want to mock using EasyMock

I would like to unit test a method with multiple internal calls to a class I want to mock using EasyMock.

The test method actually runs 5 times and calls the mocked method.

During each loop, I will create some objects, all of the same class (let's say of class A). The private method will call the mock object method that takes the instance of class A, evaluate it and return a result.

In the end, the public method will return a List of results.

I tried the standard EasyMock.expect(MockClass.method(A)).andReturn() but it does not work since there is no implementation of equals() for class A:

// this is the method example I am trying to test
public methodToTest(){
     // some logic
      privateMethodToTest(x);
     // some logic 
}
private List<B> privateMethodToTest(int x){
  List<B> list = new ArrayList<>();
  List<A> all = getObjects(x); //getObjects private method
  for (A a:all){
    list.add(objectToMock.methodToMock(a));
    return list;
  }

This is how I would like it to work:

EasyMock.createMock(ObjectToMock.class);
EasyMock.expect(ObjectToMock.methodToMock(A)/* when A.getValue() == 1 */.andReturn("B object number 1")
EasyMock.expect(ObjectToMock.methodToMock(A)/* when A.getValue() == 2 */.andReturn("B object number 2")
//... and so on 
//object of class A does not implement equals()

I am not sure how to do it and I was not able to find any similar example or answer to my question.

Upvotes: 1

Views: 471

Answers (2)

Henri
Henri

Reputation: 5731

You need another matcher. By default, EasyMock will indeed match using equals. But you can't do that. Your basic choices are:

  1. You don't care about matching precisely

If seems to be the easiest for you. It means doing:

expect(objectToMock.methodToMock(anyObject()).andReturn("B object number 1");
expect(objectToMock.methodToMock(anyObject()).andReturn("B object number 2");
  1. Use a comparator

According to your comment, you might actually prefer this

expect(mock.methodToTest(EasyMock.cmp(new A(1), Comparator.comparingInt(A::getValue), LogicalOperator.EQUAL))).andReturn(1);

The only problem is that you need a A with the correct value to compare with.

  1. To have a simplified version, you can use your own matcher

The expectation using the custom matcher right below.

expect(mock.methodToTest(cmp(0))).andReturn(3);

public static <T> T cmp(int value) {
    reportMatcher(new IArgumentMatcher() {
        @Override
        public boolean matches(Object argument) {
            return value == ((A) argument).getValue();
        }

        @Override
        public void appendTo(StringBuffer buffer) {
            buffer.append("A.value=").append(value);
        }
    });
    return null;
}

Upvotes: 1

Timothy Truckle
Timothy Truckle

Reputation: 15634

When unittesting we verify public observable behavior of the code under test, that is return values and communication with dependencies.

Anything else is implementation detail which we do not test. The reason is that you might want to refactor your code. That means you want to improve the structure of your code without changing its behavior. Your unittest schould verify that you did not change behavior accidentally. But they can only do this if you do not have to change them too.

Upvotes: 0

Related Questions