javajava-11java-http-client

How to test java.net.http (Java 11) requests BodyPublisher?


I'm trying to test my code which uses the new Java 11 java.net.http.HttpClient.

In my production code I have something like this:

HttpClient httpClient = ... (gets injected)

HttpRequest request = HttpRequest.newBuilder().uri(URI.create("http://localhost:1234"))
        .POST(HttpRequest.BodyPublishers.ofByteArray("example".getBytes()))
        .build();

return httpClient.send(request, HttpResponse.BodyHandlers.ofByteArray());

And in my test I mock the HttpClient and so get the java.net.http.HttpRequest. How do I get/test its request body (= my "example")? I can call request.bodyPublisher() to get a HttpRequest.BodyPublisher, but then I'm stuck.


Solution

  • If you are interested in how body will look like in handler you can know it with help of HttpRequest.BodyPublisher Subscriber. We call subscription.request in order to receive all body items and collect them.

    Our custrom subscriber:

    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.Flow;
    
    public class FlowSubscriber<T> implements Flow.Subscriber<T> {
        private final CountDownLatch latch = new CountDownLatch(1);
        private List<T> bodyItems = new ArrayList<>();
    
        public List<T> getBodyItems() {
            try {
                this.latch.await();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return bodyItems;
        }
    
        @Override
        public void onSubscribe(Flow.Subscription subscription) {
            //Retrieve all parts
            subscription.request(Long.MAX_VALUE);
        }
    
        @Override
        public void onNext(T item) {
            this.bodyItems.add(item);
        }
    
        @Override
        public void onError(Throwable throwable) {
            this.latch.countDown();
        }
    
        @Override
        public void onComplete() {
            this.latch.countDown();
        }
    }
    

    Usage in the test:

    @Test
    public void test() {
        byte[] expected = "example".getBytes();
    
        HttpRequest.BodyPublisher bodyPublisher =
                HttpRequest.BodyPublishers.ofByteArray(expected);
    
        FlowSubscriber<ByteBuffer> flowSubscriber = new FlowSubscriber<>();
        bodyPublisher.subscribe(flowSubscriber);
    
        byte[] actual = flowSubscriber.getBodyItems().get(0).array();
    
        Assert.assertArrayEquals(expected, actual);
    }