JUnit Test Spring Webflux

With a new way of programming, a new way of testing our code also has to come. In this post we will have a look at how we can JUnit test Spring Webflux.

Reactive Java (RxJava) has existed for a couple of years now, but it hasn’t really become mainstream yet. Mostly due to it being an external library. This has been changed since Java 9 where the standard library ships with built-in reactive support. However, that didn’t really help either as Java 9 wasn’t a LTS release which meant that most enterprises stayed on Java 8 and still do to this date.

Lucky for us developers (which developers doesn’t like  to play with new and shiny stuff?), Oracle decided to completely change the license mode and now many enterprises will now feel forced to upgrade to Java 11.

At the same time, Spring Framework 5 (included in Spring Boot 2) was released in 2018 which also comes with a reactive framework. 
Due to this, I believe that 2019 will finally be the year of reactive Java.

If you have not heard about Reactive Programming or Spring Webflux previously, then I recommend you checking out my previous article which implements a Reactive API using Couchbase.

Project Reactor

Lucky for us, there is a very powerful library for testing reactive code. Project Reactor is a library that follows the Reactive Streams Specification, which is based on Flux[N] and Mono[0|1], the same as Spring Webflux, and it also comes with some powerful tools for testing it.

Reactive Code

Let’s start with a simple method that performs division of numbers in a range and returns the result as a Flux.

public static Flux divideNumbersInRange(int start, int end, int divisor) {
  return Flux.fromStream(IntStream.range(start, end)
      .boxed())
      .map(dividend -> Double.valueOf(dividend / divisor));
}

StepVerifier

To verify the above code, we are going to utilize the StepVerifier class which is included in Project Reactor. StepVerifier is a handy tool which you can use to subscribe to a producer and then verify the steps in the subscription.

The first obvious cases to test is sunny-day executions, meaning with valid input that it produces the expected result. Also, note that I did a static import of the static method that we are going to test just to make the code a bit cleaner.

@Test
public void givenDivisionByOneItemThenExpectOneItem() {
  StepVerifier.create(divideNumbersInRange(1, 2, 1))
      .assertNext(result -> assertEquals(1.0, result, 0.01))
      .expectNextCount(1)
      .verifyComplete();
}

@Test
public void givenDivisionByFourItemsThenExpectFourItems() {
  StepVerifier.create(divideNumbersInRange(1, 5, 1))
      .expectNextCount(4)
      .verifyComplete();
}

@Test
public void givenDivisionByZeroItemsThenExpectEmptyFlux() {
  StepVerifier.create(divideNumbersInRange(1, 1, 1))
      .expectNextCount(0)
      .verifyComplete();
}

In the first test, we verify that it produces the right answer when we perform just one division. We utilize the assertNext method where we can add all the types of assertions that we might be interested to do before proceeding. In the following tests, we verify that the ranges work as expected and that it produces the correct number of items (nexts) in the Flux.

Please note the .verifyComplete() call at the end, this one is very important as the StepVerifier won’t subscribe to the provided Publisher in the create method. There are different verifying methods available, but at least one of them has to be called, otherwise the code won’t be executed, as a producer only produces if someone is subscribing to it.

Error Handling

If some exception happens in the producer, an error is not thrown the way that we are used to, instead it is returned in the error channel. The traditional JUnit tests where you annotate that you expect an exception will be thrown won’t work anymore @Test(expected = ArithmeticException.class). Instead, we have to instruct the StepVerifier that we expect an error to be thrown.

@Test
public void givenDivisionByZeroThenExpectException() {
  StepVerifier.create(divideNumbersInRange(1, 2, 0))
      .expectError()
      .verifyThenAssertThat()
      .hasOperatorErrorOfType(ArithmeticException.class);
}

We try to divide by zero which means we will expect an ArithmeticException.

Conclusion

The often said statement that it is hard to JUnit test Spring Webflux is just not true in my opinion. You just gotta use the default tools for it. As reactive programming is a completely different way to write code, then it is wrong to assume that you should be able to write unit tests the same way that you did previously.

StepVerifier in Project Reactor gives us a very powerful DSL for testing our reactive code, and in my opinion, the unit test code looks beautiful using it. 🙂

Leave a Reply