Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

  • I've tried to cast it to jdk.internal.net.http.RequestPublishers.ByteArrayPublisher (which it actually is), but it won't compile because the corresponding package is not exported by the module.
  • I've checked the available methods in the HttpRequest.BodyPublisher-interface (.contentLength(), .subscribe(subscriber)) but I guess it's not possible with them.
  • I've tried to just create a new BodyPublisher and compare them using .equals(), but there is no real implementation of it and so the comparison was always false.
like image 970
Itchy Avatar asked Dec 15 '19 10:12

Itchy


People also ask

What is BodyPublisher Java?

Enclosing class: HttpRequest public static class HttpRequest.BodyPublishers extends Object. Implementations of BodyPublisher that implement various useful publishers, such as publishing the request body from a String, or from a file.

Is Java net HttpClient thread safe?

HttpClient is fully thread-safe when used with a thread-safe connection manager such as MultiThreadedHttpConnectionManager.

What is HttpRequest in Java?

An HTTP request. An HttpRequest instance is built through an HttpRequest builder. An HttpRequest builder is obtained from one of the newBuilder methods. A request's URI , headers, and body can be set. Request bodies are provided through a BodyPublisher supplied to one of the POST , PUT or method methods.

Can we use HttpClient in Java 8?

Is there any way to use it in java 8? No, because the jdk. incubator. http module has been added since Java 9.


1 Answers

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);
}
like image 189
Yan Avatar answered Oct 06 '22 01:10

Yan