简体   繁体   中英

mockito verifying polymorphic methods

I'm trying to verify call to a polymorphic method using mockito, and am confused about what the best way forward is.

Example Class

public class Library {
    public boolean foo() {
        return true;
    }
    public boolean foo(String s) {
        return true;
    }
    public boolean foo(Integer s) {
        return true;
    }
}

The test class using mockito(ignore the fact that in LibraryTest class, Library is not the class-under-test, but rather I'm mocking it)

import org.junit.Test;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
public class LibraryTest {
    @Test public void testFoo1() {
        Library mockLibrary = mock(Library.class);
        mockLibrary.foo("Hi");
        verify(mockLibrary).foo(any());
    }
    @Test public void testFoo2() {
        Library mockLibrary = mock(Library.class);
        verify(mockLibrary, never()).foo(any());
    }
}

So both the verify statements don't compile, with the error "The method foo(String) is ambiguous for the type Library".

The error kind of makes sense, any() tries to return a captor based on the type of the argument but the argument could be Integer or String or void .

What I want to achieve is that in both the tests, a call to any of the foo methods is counted by the verify . In other words the first verify call should succeed if I called any of the foo methods and the second verify should fail if I call any of the foo methods.

Is there a way to make this happen?

You can use isA matcher

verify(mockLibrary).foo(isA(Integer.class));

verify(mockLibrary).foo(isA(String.class));

and btw use Mockito.spy instead of Mockito.mock when you only want to see if some methods have been called on the class under test

EDIT with example (written in few minutes, don't mind the code:)) based on the new op details.

public static class Library {
    public boolean foo() {
        return true;
    }

    public boolean foo(String s) {
        return true;
    }

    public boolean foo(Integer s) {
        return true;
    }

    public String x(){
        return "";
    }

    public void y(){
        return;
    }
}


public static class ResponseProvider {
    public boolean result;
}

@Test
public void testFoo1() {
    final ResponseProvider provider = new ResponseProvider();
    provider.result = false;
    Library lib = Mockito.mock(Library.class, new Answer<Object>() {
        @Override
        public Object answer(InvocationOnMock invocation) throws Throwable {
            if ((invocation.getMethod().getName().equals("foo"))) {
                provider.result = true;
                return true;
            }
            return invocation.callRealMethod();
        }
    });

    //lib.foo();
    //lib.x();
    //lib.y();
    assertTrue(provider.result);

}

First of all, You are mocking the same class which you are testing. Thats not advisable but still

Its giving this exception because mockito doesn't know which method you are verifying among the foo methods. If you want to make sure the method you invoked is called with the right value, you can either use isA(ClassName) matcher or use can use ArgumentCaptor.

Example of ArgumentCaptor

@Test public void testFoo1() {
    Library mockLibrary = mock(Library.class);
    mockLibrary.foo("Hi");
    ArgumentCaptor<String> stringCaptor = ArgumentCaptor.forClass(String.class);

    verify(mockLibrary).foo(stringCaptor.capture());
    String actualArgument = stringCaptor.getValue();

    assertEquals(actualArgument, "Hi");
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM