Reputation: 541
For JUnit testing I want to mock an overloaded method. There is no need to implement several methods in the mockbuilder though. I want to do something like this:
Mockito.when(mock.getSomeInfo(Mockito.any(ArgumentType1.class) OR Mockito.any(ArgumentType2.class), Mockito.any(ArgumentType3.class))).then(new Answer<AnswerType>() {..}
I know it doesn't work with the OR
statement, but is there another way to do this in Mockito?
Upvotes: 13
Views: 26986
Reputation: 39287
You can do this with a custom matcher.
Warning: Be reasonable with using complicated argument matching, especially custom argument matchers, as it can make the test less readable. Sometimes it's better to implement equals() for arguments that are passed to mocks (Mockito naturally uses equals() for argument matching). This can make the test cleaner.
public class TypeOrMatcher extends ArgumentMatcher<Object> {
private final List<Class<?>> clazzes;
public TypeOrMatcher(Class<?>...clazzes) {
this.clazzes = new ArrayList<Class<?>>(clazzes);
}
public boolean matches(Object actual) {
if (actual == null) {
return false;
}
Class<?> actualClass = actual.getClass();
for (Class<?> clazz : clazzes) {
if (clazz.isAssignableFrom(actualClass) {
return true;
}
}
return false;
}
}
TypeOrMatcher isTypeOneOrTwo = new TypeOrMatcher(
ArgumentType1.class, ArgumentType2.class);
Some mockObj = mock(Some.class);
when(mockObj.someMethod(argThat(isTypeOneOrTwo), any(ArgumentType3.class))
.thenReturn(true);
Upvotes: 2
Reputation: 701
As mentioned on the mockito github:
It looks like this has to do with calling when the second time. I couldn't find what was going on, but the second when doesn't attempt to add the mock logic, it just calls the method. Replacing with doReturn().when() works.
doReturn(expected1).when(overloadedMethods).getString(any());
doReturn(expected2).when(overloadedMethods).getString(any(), any());
https://github.com/mockito/mockito/issues/1496#issuecomment-423310950 DavidTanner
Upvotes: 3
Reputation: 129
For an example I have a service class that will be called from testing method:
public interface AService{
public ReturnObject addNewItem(String param1, String param2);
public ReturnObject addNewItem(String param1, String param2, boolean isOk);
}
Have a method in MainServiceImpl class will call an overloaded method like below:
@Service("mainService")
public class MainServiceImpl implements MainService {
@Autowired
private AService aService;
public ReturnObject saveItem(String itemName, String itemCode){
return aService.addNewItem(itemName, itemCode);
}
}
So when we have to write unit test for saveItem
the method which already calls to overloaded method as addNewItem
, if you had used normal way to create a mock then you answer will not return what you want in answer object return.
@RunWith(PowerMockRunner.class)
@PrepareForTest({ })
public class ItemTest{
@Test
public void testSaveItem() throws Exception {
//create a real object of MainServiceImpl
MainServiceImpl mainService = new MainServiceImpl();
//create a normal way for a mocking object
AService aService = Mockito.mock(AService.class);
// Add mock object to MainServiceImpl instance
ReflectionTestUtils.setField(mainService, "aService", aService);
//Mock when aService call to addNewItem() method
PowerMockito.when(aService , "addNewItem", Mockito.anyString(), Mockito.anyString()).then(new Answer<ReturnObject>() {
@Override
public ReturnObject answer(InvocationOnMock invocation) throws Throwable {
return new ReturnObject("saveOK");
}
});
ReturnObject returnObj = mainService.saveItem("Book", "Code123");
Assert.assertNotNull(returnObj);
}
}
Try to replace testSaveItem above by with testSaveItem below then success:
@Test
public void testSaveItem() throws Exception {
//create a real object of MainServiceImpl
MainServiceImpl mainService = new MainServiceImpl();
//create a special way for a mocking object by add
//the answer at create the mock object
final Answer<ReturnObject> answer = new Answer<ReturnObject>() {
@Override
public ReturnObjectanswer(final InvocationOnMock invocation) throws Throwable {
return new ReturnObject("saveOK");
}
};
AService aService = Mockito.mock(AService.class, answer);
// Add mock object to MainServiceImpl instance
ReflectionTestUtils.setField(mainService, "aService", aService);
//Mock when aService call to addNewItem() method
PowerMockito.when(aService , "addNewItem", Mockito.anyString(), Mockito.anyString()).then(new Answer<ReturnObject>() {
@Override
public ReturnObject answer(InvocationOnMock invocation) throws Throwable {
return new ReturnObject("saveOK");
}
});
ReturnObject returnObj = mainService.saveItem("Book", "Code123");
Assert.assertNotNull(returnObj);
}
Upvotes: 0
Reputation: 768
You can pre-create the answer object you want to return and then return this answer.
class A {
public int test(final String s) {
return 0;
}
public int test(final int i) {
return 0;
}
}
And in the test method:
public void testAtest() {
final A a = Mockito.mock(A.class);
final Answer<Integer> answer = new Answer<Integer>() {
@Override
public Integer answer(final InvocationOnMock invocation) throws Throwable {
return 0;
}
};
Mockito.when(a.test(Matchers.anyInt())).then(answer);
Mockito.when(a.test(Matchers.anyString())).then(answer);
}
Upvotes: 1