3

I wanted to use reactive programming inside the JUnit testing framework to do system tests on a remote rest api.

I thus wrote:

  @Test
  void testWebClient() {
    WebClient webClient = WebClient.builder()
        .baseUrl(GITHUB_API_BASE_URL)
        .defaultHeader(HttpHeaders.CONTENT_TYPE, GITHUB_V3_MIME_TYPE)
        .defaultHeader(HttpHeaders.USER_AGENT, USER_AGENT)
        .filter(ExchangeFilterFunctions
            .basicAuthentication(appProperties.getGithub().getUsername(),
                appProperties.getGithub().getToken()))
        .build();

    var response = webClient.get()
        .uri("/user/repos?sort={sortField}&direction={sortDirection}",
            "updated", "desc")
        .exchange()
            .doOnError(e -> {
              System.out.println(e.toString());
            })
            .subscribe(r -> {
              System.out.println(r  );
            });
  }

to get all my github repos. I kept catching this error:

java.lang.IllegalStateException: executor not accepting a task

until add ".block()" after ".exchange()" to do the call synchronously and everything start to work fine.

I suspect JUnit to start a special thread context or something like that. Do you know what can is happening?

Thanks a lot

2 Answers2

7

The problem is that once the function testWebClient() finish, all the asynchronous process are closed.

In this case you are using WebClient that is an async job, so the function testWebClient() finish before the WebClient can get the answer.

In order to prevent this, you can:

  • use a thread sleep method like TimeUnit.SECONDS.sleep(5).
  • use an external library like Awaitility

Example with Awaitility


bool taskDone = false;
@Test
void testWebClient() {
    //...
    var response = webClient.get()
    //...
    .doFinally(r->{
        taskDone = true;
    })

    await().until(()-> taskDone);
}

So in this case the function will wait until the task complete.

Bill Horvath
  • 1,336
  • 9
  • 24
David A.
  • 191
  • 3
  • 1
    Another option to using sleep or an external library is to just make the web client call a blocking call. Your code could be something like this: `var resp = webClient.get().uri(url).retrieve().toEntity(String.class).block(); assertEquals(HttpStatus.OK, resp.getStatusCode());` – Daniel H. Dec 23 '22 at 17:13
0

Another option is to use StepVerifier in your test case.

    StepVerifier.create(<flux>)
      .expectSubscription()
      .consumeNextWith(e-> log.debug(e.toString()))      
      .thenAwait().verifyComplete();

will need the following dependency

    <dependency>
        <groupId>io.projectreactor</groupId>
        <artifactId>reactor-test</artifactId>
        <scope>test</scope>
    </dependency>
user645527
  • 93
  • 6