Henrique
Henrique

Reputation: 221

How can I create a header response for unit tests?

I have some method that sends a request and receive a response. I get the response in header, it's a String.

My method:

@Override
    public String myMethod(SomeClass someItem) {
        try {

            HttpRequest request = HttpRequest.newBuilder()
                    .POST(HttpRequest.BodyPublishers.ofString(myBodyString))
                    .uri(getUri())
                    .header(OAUTH, getToken())
                    .headers(KEY_HEADER, valueHeader)
                    .headers(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
                    .build();

            var response = httpClient.send(request, HttpBodyHandlers.ofCodec());

            if (response.statusCode() == HttpStatus.OK.value()) {
                return response.headers().allValues(LOCATION).get(0);
            } else {
                log.warn(ERROR_LOG + response.statusCode());
                return null;
            }
        } catch (Exception e) {
            log.error(ERROR_LOG + e.getCause());
            return null;
        }
    }

I'm trying do assert this response in my test, but without success. My test:

@ExtendWith(MockitoExtension.class)
class ClassToTest {

    private final static String URL = "https://myUrl/";
    private final static String ACCESS_TOKEN = "access_token";

    private final Clock clock = Clock.fixed(Instant.now(), ZoneId.of("UTC"));

    private ClassToTest service;

    @Mock
    private HttpClient httpClient;

    @Mock
    private OAuth oAuthClient;

    @Mock
    private HttpResponse httpResponse;

    @BeforeEach
    void setUp() {
        service = new ClassToTest(httpClient, oAuthClient);
        when(config.getValue(SERVICE_URL)).thenReturn(AVISO_URL);
        when(oAuthClient.getToken()()).thenReturn(ACCESS_TOKEN);
    }

    @Test
    void myMethod_toTest_success() throws IOException, InterruptedException {
        when(httpClient.send(any(HttpRequest.class), any(HttpResponse.BodyHandler.class))).thenReturn(httpResponse);
        when(httpResponse.statusCode()).thenReturn(HttpStatus.OK.value());

        var result = service.myMethod(myItem);
        assertEquals("UUID", result);
    }
...
}

I'm not able to create a expected item to assert my result. I'm getting null on my result

Upvotes: 1

Views: 2014

Answers (2)

Arho Huttunen
Arho Huttunen

Reputation: 1131

There's not much benefit in mocking the framework calls in a case like this, although it could be possible. You end up mocking everything and duplicate almost all of the production code to match the usage.

Try using something like MockWebServer instead:

class ClassToTest {
    private MockWebServer mockWebServer;

    @BeforeEach
    void init() {
        this.mockWebServer = new MockWebServer();
    
        when(config.getValue(SERVICE_URL))
            .thenReturn(mockWebServer.url("/").toString());

        // ...
    }

    @Test
    void myMethod_toTest_success() {
        mockWebServer.enqueue(new MockResponse()
            .addHeader(LOCATION, "UUID")
            .setBody("some response")
            .setResponseCode(200));

        var result = service.myMethod(myItem);
        assertEquals("UUID", result);
    }
}

There's a small overhead of starting the MockWebServer but your test doesn't have to try to replicate what HttpClient really does.

Upvotes: 1

Ryuzaki L
Ryuzaki L

Reputation: 39978

Instead of mocking HttpRespone object calls i will recommend to create. HttpResponse object with corresponding values

   HttpResponse<String> httpResponse = new HttpResponse<String>() {
        @Override
        public int statusCode() {
            return 200;
        }

        @Override
        public HttpRequest request() {
            return null;
        }

        @Override
        public Optional<HttpResponse<String>> previousResponse() {
            return Optional.empty();
        }

        @Override
        public HttpHeaders headers() {
            return HttpHeaders.of(Map.of("", List.of()), (v1,v2)->true);
        }

        @Override
        public String body() {
            return null;
        }

        @Override
        public Optional<SSLSession> sslSession() {
            return Optional.empty();
        }

        @Override
        public URI uri() {
            return null;
        }

        @Override
        public HttpClient.Version version() {
            return null;
        }
    };

Upvotes: 2

Related Questions