Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use ArgumentCaptor with Mockito.when().thenReturn()

I have a use case in which I want to capture values passed in the method and also use this value to define Mockito behaviour.

Like this :

@InjectMocks
private ClassUnderTest classUnderTest;

@Mock
private MockedClass mockedClass;

@Captor
private ArgumentCaptor<ArgumentUsedInMockedClass> captor;

@Test
public void testMethod() {
    Result result = new Result();
    result.setResultId(RESULT_ID);

    Mockito.verify(mockedClass).doSomething(captor.capture());

    Mockito.when(mockedClass.doSomething(captor.getValue())).thenReturn(result);

    Assert.assertTrue(classUnderTest
            .doSomething(foo, bar)
            .equals(result));
}

But I'm getting this error :

[junit] Wanted but not invoked:
[junit] mockedClass.doSomething(
[junit]     <Capturing argument>
[junit] ); 
[junit] Actually, there were zero interactions with this mock.

In my doSomething() function, foo and bar are used to generate argument of type ArgumentUsedInMockedClass. Now, this ArgumentUsedInMockedClass type doesn't have its equals() defined properly and hence it's failing ambigously if I'm trying to directly use

Mockito.when(mockedClass.doSomething(argumentUsedInMockedClass)).thenReturn(result); with argumentUsedInMockedClass being generated in the test method even though it's params are same. I'm trying to capture the exact object being created in this ClassUnderTest to define mockito behaviour, but it looks to me like a cycle where first

Assert.assertTrue(classUnderTest
            .doSomething(foo, bar)
            .equals(result));

has to happen to actually capture, but for it to work mockedClass behaviour should be defined which is depending on it.

How do I get around this situation or use some another testing approach?

like image 771
dushyantashu Avatar asked Dec 15 '16 15:12

dushyantashu


1 Answers

You get the error because you try to verify if the method is called before it is actually called, which happens in assertTrue.

You could rewrite your test like this:

@Test
public void testMethod() {
    Result result = new Result();
    result.setResultId(RESULT_ID);

    // Define the behavior
    Mockito.when(mockedClass.doSomething(any(ArgumentUsedInMockedClass.class)).thenReturn(result);

    Assert.assertTrue(classUnderTest
            .doSomething(foo, bar)
            .equals(result));
    Mockito.verify(mockedClass).doSomething(captor.capture());
    ArgumentUsedInMockedClass argument = captor.getValue();
    // Do some further verification/assertion with argument
}
like image 59
hotzst Avatar answered Sep 29 '22 11:09

hotzst