xetra11
xetra11

Reputation: 8895

Mockito mock a method but use its parameters for the mocked return

There is a method public Content createChild(String path, String contentType, Map<String,Object> properties) I'd like to mock.

I want to mock it that way that the method is called with any kind of arguments, therefore when() wouldn't work because I have to tell it what arguments the method should receive to be actually mocked.

So I want to actually react on any method call independent of its given arguments (use spies?) and then call some kind of "callback" to return a Content object which I want build together out of the real arguments given to the method.

I could not find a specific API in Mockito which supports this.

Upvotes: 8

Views: 20879

Answers (4)

Vijay
Vijay

Reputation: 5050

You can try something like with use of eq() and any() as per as your requirement:

when(service.createChild(eq("helloe/hi"), any(String.class), any(Map.class)))
     .thenReturn(any(Content.class));

eq - If we want to use a specific value for an argument, then we can use eq() method.

any - Sometimes we want to mock the behavior for any argument of the given type

Upvotes: 0

Vadeg
Vadeg

Reputation: 1176

Sure you can. I have written simple unit test for this

public class MockitoTest {


    private SampleService sampleService;

    @Before
    public void setUp() throws Exception {
        sampleService = Mockito.mock(SampleService.class);
    }

    @Test
    public void mockitoTest() throws Exception {
        when(sampleService.createChild(anyString(), anyString(), anyMapOf(String.class, Object.class)))
            .thenAnswer(invocationOnMock -> {
                //Here you can build result based on params
                String pathArg = (String) invocationOnMock.getArguments()[0];
                if (pathArg.equals("p1")) {
                    return new Content("Content for p1");
                } else if (pathArg.equals("p2")) {
                    return new Content("Content for p2");
                } else {
                    return invocationOnMock.callRealMethod();
                }
            });

        Content content = sampleService.createChild("p1", "any", new HashMap<>());
        assertEquals("Content for p1", content.getData());

        content = sampleService.createChild("p2", "any", new HashMap<>());
        assertEquals("Content for p2", content.getData());

        content = sampleService.createChild("whatever", "any", new HashMap<>());
        assertEquals("original", content.getData());

    }

    /**
     * Sample service with method
     */
    private static class SampleService {

        public Content createChild(String path, String contentType, Map<String, Object> properties) {
            return new Content("original");
        }

    }

    /**
     * Content example
     */
    private static class Content {

        private String data;

        Content(String data) {
            this.data = data;
        }

        String getData() {
            return data;
        }
    }

}

Upvotes: 5

birkett
birkett

Reputation: 10141

You can use matchers

MyClass m = mock(MyClass.class);
when(m.createChild(any(String.class), any(String.class), any(Map.class))).thenReturn(new Content());

You should also be able to use the parameters this way

when(m.createChild(any(String.class), any(String.class), any(Map.class))).thenAnswer(
       new Answer<Content>()
       {
           @Override
           public Content answer(final InvocationOnMock invocation) throws Throwable
           {
               return new Content((String) invocation.getArguments()[0], 
(String) invocation.getArguments()[1],
(Map) invocation.getArguments()[2]);
               }
           }
       }
       );

Upvotes: 1

thegauravmahawar
thegauravmahawar

Reputation: 2823

You can use Matchers:

You can try something like:

when(service.createChild(anyString(), anyString(), anyMap()))
     .thenReturn(any(Content.class));

Upvotes: 6

Related Questions