Kong / unirest-java

Unirest in Java: Simplified, lightweight HTTP client library.
http://kong.github.io/unirest-java/
MIT License
2.58k stars 591 forks source link

ObjectMapper throws exception while serializing MockResponse #416

Closed emystein closed 2 years ago

emystein commented 2 years ago

Describe the bug When MockClient is used and MockResponse.bad is expected, an Exception is thrown while serializing the Response.

To Reproduce Steps to reproduce the behavior:

import kong.unirest.HttpMethod;
import kong.unirest.MockClient;
import kong.unirest.MockResponse;
import kong.unirest.Unirest;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

class MockResponseTest {
    @Test
    void shouldSerializeMockResponse() {
        var mock = MockClient.register();

        mock.expect(HttpMethod.GET, "http://zombo.com")
                .thenReturn(MockResponse.bad("Bad Request"));

        var httpResponse = Unirest.get("http://zombo.com").asString();

        assertEquals(400, httpResponse.getStatus());

        mock.verifyAll();
    }
}

Stack trace:

    java.lang.IllegalArgumentException: class kong.unirest.MockConfig declares multiple JSON fields named client
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:172)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102)
        at com.google.gson.Gson.getAdapter(Gson.java:458)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:117)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:166)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102)
        at com.google.gson.Gson.getAdapter(Gson.java:458)
        at com.google.gson.Gson.toJson(Gson.java:696)
        at com.google.gson.Gson.toJson(Gson.java:683)
        at com.google.gson.Gson.toJson(Gson.java:638)
        at com.google.gson.Gson.toJson(Gson.java:618)
        at kong.unirest.JsonObjectMapper.writeValue(JsonObjectMapper.java:54)
        at kong.unirest.Invocation.lambda$thenReturn$3(Invocation.java:76)
        at kong.unirest.Invocation.getResponse(Invocation.java:81)
        at kong.unirest.Routes.lambda$exchange$0(Routes.java:62)
        at java.base/java.util.Optional.map(Optional.java:265)
        at kong.unirest.Routes.exchange(Routes.java:62)
        at kong.unirest.MockClient.request(MockClient.java:93)
        at kong.unirest.Client.request(Client.java:57)
        at kong.unirest.BaseRequest.request(BaseRequest.java:353)
        at kong.unirest.BaseRequest.asString(BaseRequest.java:206)
        at ar.com.flow.unirest.MockResponseTest.shouldSerializeMockResponse(MockResponseTest.java:19)

Expected behavior The test shown in the steps to reproduce the issue should pass.

Environmental Data:

A project ready to reproduce the issue can be found at: https://github.com/emystein/unirest-mock-response-serialization-issue

ryber commented 2 years ago

Interestingly, it was never the intention to use MockResponse in this way. It's kind of a stand-alone thing for use in more traditional testing and wasn't designed to interact with the MockClient's response builder. However, it's certainly logical to think it would work this way. So I fixed it so it can. 3.13.2 should be available in in the next few hours or so (Maven Central is a mystery about when things show up after publishing)

Note that what you end up getting back is NOT the MockResponse itself, but a copy of it. https://github.com/Kong/unirest-java/blob/main/unirest-mocks/src/test/java/kong/tests/ExpectedResponseTest.java#L153-L196

emystein commented 2 years ago

Excellent, thanks for the clarification and the fix @ryber!