How to get value from a private method's return value in test

Viewed 1231

I am trying to write a test for the following scenario. I want to mock that restCallReturningAString() method call.

Now I could just do the following which would work.

when(restCallReturningAString(any()).thenReturn("some text String");

But I am looking to be able to pass in an actual value instead of just using any().

I cant just create a new Request object in my test method cos it would not match. This is cos there is no Object equals override for the Request Object and other Objects in it. I do not want to add equals override for the sake of testing.

How do I capture the value of the request object, to be able to use it in my test? I am not familiar with ArgumentCapture and was trying to see if that would help with this but no luck. Appreciate any help. I want to stick to Mockito version 1.10 only. I do not want to use PowerMock or any additional libraries for this. Thanks.

Class Being tested

public class SomeClass {

    @Autowired
    private AnotherClass anotherClass;

    public String getData(String name){
        ExternalData externalData = new ExternalData();
        List<InnerObject> innerObjects = Collections.singletonList(new InnerObject());
        externalData.setInnerObjects(innerObjects);

        // Question is how do I capture the value of request here? 
        Request request = getRequest(externalData, name);

        String s = anotherClass.restCallReturningAString(request);
        //other logic
        return "some String";
    }

    private Request getRequest(ExternalData externalData, String name){
        // other logics
        Request request = new Request();
        request.setName(name);
        request.setExternalData(externalData);
        return request;
    }
}

// all following classes in their own separate files

@Getter
@Setter
class Request {
    private String name;
    private ExternalData externalData;
}

@Getter
@Setter
class ExternalData {
    private String color;
    private List<InnerObject> innerObjects;
}

@Getter
@Setter
class InnerObject {
    private String name;
} 

If I can capture that value, trying to test as follows:

@Test
public void someTest(){
    // This is the issue. Looking to be able to capture this value
    Request request = // got the value with a solution

    when(anotherClass.restCallReturningAString(request)).thenReturn("some test text");
    // instead of
    // when(anotherClass.restCallReturningAString(any())).thenReturn("some test text");

    String s = someClass.getData("name");
    assertEquals("expected", s);
}
2 Answers

As written in my comment: You can use an ArgumentCaptor to capture the value that was passed to your method. You can then verify if the passed argument is the correct one.

Example code:

@Test
public void someTest(){
    ArgumentCaptor<Request> requestArgumentCaptor = ArgumentCaptor.forClass(Request.class);
    when(anotherClass.restCallReturningAString(requestArgumentCaptor.capture())).thenReturn("some test text");

    String s = someClass.getData("name");
    assertEquals("expected", s);

    //  verify that the method was called only once
    assertEquals(1, requestArgumentCaptor.getAllValues().size());

    // verify the restCallReturningAString method was called with the correct values for request
    assertEquals("expectedName", requestArgumentCaptor.getValue().getName());
    assertEquals("expectedColor", requestArgumentCaptor.getValue().getExternalData().getColor());
    // and so on
}

Spy the target test class and write the test case like this:

@Test
public void someTest(){
    // Arrange
    SomeClass spyClass = spy(someClass);
    Request request = // got the value with a solution;
    when(spyClass.getRequest(externalData, name)).thenReturn(request);
    when(anotherClass.restCallReturningAString(request)).thenReturn("some test text");

    // Act
    String actual = spyClass.getData("name");

    // Assert
    assertEquals("expected", actual);
}
Related