3

I am in my starting programming phase and I wanted to ask about mocking Objects with Mockito, more specifically is the Unirest response. Let's say I have a database, and I dont what to bother it every time I do testing, and I want to use Mockito for that, but the problem is I am not sure how to create the fake "httpResponse" object that will come back. To give some context, I have attached my code:

    /**
 * This method lists the ID of the activity when requested.
 *
 * @return the list of all activities
 */
public  JSONArray getActivites() {
    HttpResponse<JsonNode> jsonResponse = null;
    try {
        jsonResponse = Unirest
                .get("http://111.111.111.111:8080/activity")
                .header("accept", "application/json")
                .asJson();
    } catch (UnirestException e) {
        System.out.println("Server is unreachable");
    }

    JSONArray listOfActivities = jsonResponse.getBody().getArray();
    return listOfActivities;
}

So what I had in mind, is to mock Unirest, and then when a .get method gets invoked, I would return a fake HttpResponse, problem is, I am not sure how to, I have looked online and couldn't really make much sense of it. Is it possible to do it 1 time with the actual Database, and then "Extract" the information and to use that every time for testing?

Bar Lerer
  • 89
  • 3
  • 10

5 Answers5

6

Sample Snippet with PowerMockRunner, PowerMockito and Mockito

@RunWith(PowerMockRunner.class)
    @PrepareForTest({ Unirest.class})
    public class TestApp{

      @Before
      public void setup() {
        PowerMockito.mockStatic(Unirest.class);
      }

      @Test
      public void shouldTestgetActivites() throws UnirestException {
        when(Unirest.get(Client.DEFAULT_BASE_URL)).thenReturn(getRequest);
        when(getRequest.asJson()).thenReturn(httpResponse);
        when(httpResponse.getStatus()).thenReturn(Integer.valueOf(200));

        assertThat(something).isEqualTo(true);
      }

    }
Mebin Joe
  • 2,172
  • 4
  • 16
  • 22
  • So I have been looking at your snippet, and in that line: ```when(Unirest.get(Client.DEFAULT_BASE_URL)).thenReturn(getRequest);``` I dont understand what "getRequest" that will be returned when Unirest.get gets invoked. Is that the "getRequest" object? – Bar Lerer Mar 19 '19 at 10:15
  • @BarLerer Yes. It is a mock for GetRequest. You could refer this for more details. https://github.com/thejamesthomas/javabank/blob/master/javabank-client/src/test/java/org/mbtest/javabank/ClientTest.java – Mebin Joe Mar 19 '19 at 10:22
2

Instead of directly calling a static member, you could wrap the call in a wrapper class that can supply an HttpResponse based on some arguments. This is an interface that can easily be mocked in Mockito.

/**
 * This is a wrapper around a Unirest API.
 */
class UnirestWrapper {

    private HttpResponse<JsonNode> getResponse(String accept, String url) {
        try {
            return Unirest
                .get(url)
                .header("accept", accept)
                .asJson();
        } catch (UnirestException e) {
            System.out.println("Server is unreachable");
        }
        // Or create a NULL HttpResponse instance.
        return null;
    }
}

private final UnirestWrapper unirestWrapper;

ThisClassConstructor(UnirestWrapper unirestWrapper) {
    this.unirestWrapper = unirestWrapper;
}

/**
 * This method lists the ID of the activity when requested.
 *
 * @return the list of all activities
 */
public JSONArray getActivites() {
    HttpResponse<JsonNode> jsonResponse = this.unirestWrapper.getResponse("http://111.111.111.111:8080/activity", "application/json");

    if (jsonResponse == null) {
        return null;
    }

    JSONArray listOfActivities = jsonResponse.getBody().getArray();
    return listOfActivities;
}

Or you could use power mocks...

James
  • 1,095
  • 7
  • 20
2

In the meantime the orignal authors provide mocking support with unirest-mocks:

Maven:

<dependency>
    <groupId>com.konghq</groupId>
    <artifactId>unirest-mocks</artifactId>
    <version>LATEST</version>
    <scope>test</scope>
</dependency>

Usage:

class MyTest {
    @Test
    void expectGet(){
        MockClient mock = MockClient.register();

        mock.expect(HttpMethod.GET, "http://zombo.com")
                        .thenReturn("You can do anything!");
        
        assertEquals(
            "You can do anything!", 
            Unirest.get("http://zombo.com").asString().getBody()
        );
        
        //Optional: Verify all expectations were fulfilled
        mock.verifyAll();
    }
}
timomeinen
  • 3,101
  • 3
  • 33
  • 46
  • Unfortunately it does not work. HttpMethod.GET should be from kong.unirest.HttpMethod and it does not exist in jar file. I tried 3.11.09 – Rita May 01 '22 at 17:13
  • @Rita `kong.unirest.HttpMethod` is the real object that is part of `unirest-java`. The dependency is marked as `provided` in `unirest-mocks`, so the dependency must be added to the project's pom.xml. – timomeinen May 03 '22 at 18:41
0

You can mock the HttpResponse with Mockito.mock(HttpResponse.class) and put to when get the body of this response to get your json. For example:

HttpResponse response = Mockito.mock(HttpResponse.class);    
when(response.getBody()).thenReturn(readFileContent("my_response.json"));

this 'readFileContent' is just a method to read a file where I put my response. You can put your json to compare there

Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
Thiago Gregorio
  • 231
  • 2
  • 4
0

I solved similar task by using JUnit5 and Mockito. Class under test:

@Service
@RequiredArgsConstructor
@Profile("someProfile")
@Slf4j
public class SomeService {
    
    @Value("${value1}")
    private final String value1;

    @Value("${value2}")
    private final String value2;

    private final ObjectMapper mapper;
    private final CommonUtil commonUtil;

    public boolean methodUnderTest(String inputValue) {
        HttpResponse<String> result;
        //some logic 
        try {
            result = Unirest.get("url")
                    .header(header, value)
                    .routeParam("param", paramValue)
                    .asString();
            if (result.getStatus() != 200) {
                throw new MyException("Message");
            }
            //some logic
        } catch (Exception e) {
            log.error("Log error", e);
            //some logic
        }
    }
}

And test:

@ExtendWith(MockitoExtension.class)
class SomeServiceTest {
    @Mock
    private CommonUtil commonUtil;
    @Mock
    private ObjectMapper mapper;
    @Mock
    HttpResponse httpResponse;
    @Mock
    GetRequest request;

    private SomeService serviceUnderTest;


    @BeforeEach
    void setUp() {
        this.serviceUnderTest = new SomeService("url", "valu1", mapper, commonUtil);
    }

    @Test
    void methodUnderTest_whenSmth_ThenSmth() throws UnirestException {
        try (MockedStatic<Unirest> unirest = Mockito.mockStatic(Unirest.class)) {
            unirest.when(() -> Unirest.get(anyString()))
                    .thenReturn(request);

            Mockito.when(commonUtil.encodeValue(Mockito.anyString())).thenReturn("123");

            Mockito.when(request.header(anyString(), anyString())).thenReturn(request);
            Mockito.when(request.routeParam(anyString(), anyString())).thenReturn(request);
            Mockito.when(request.asString()).thenReturn(httpResponse);


            Mockito.when(httpResponse.getStatus()).thenReturn(200);
            Mockito.when(httpResponse.getBody()).thenReturn("true");
            assertTrue(serviceUnderTest.methodUnderTest("123"));
        }
    }
 }   
Rita
  • 81
  • 4