Search code examples
quarkussmallryemutinysmallrye-reactive-messaging

How to unit test a method returning Uni/Multi of Smallrye mutiny reactive library?


I am using Smallrye Mutiniy reactive library in my Quarks application as it is supported natively in Quarks applications.

I'am trying to write unit tests for a service class. I am not sure how to write unit tests for a method that returns Uni/Multi.

A method returning Uni<String>

public Uni<String> hello(final String name) {
    final String message = "Hello " + name;
    return Uni.createFrom().item(message);
}

Unit implemented for the above method

@Test
void testHello() {
    final Uni<String> casePass = hello("Ram");
    // assertion passes and all good with this.
    casePass.subscribe().with(message -> Assertions.assertEquals("Hello Ram", message));
    
    final Uni<String> caseFail = hello("Ravan");
    //  It is expected to fail the assertion, and it does. But the test is not failing, instead aseertion fail message simply logged to the console.
    caseFail.subscribe().with(message -> Assertions.assertEquals("Hello Sita", message));
}

Console logs

[-- Mutiny had to drop the following exception --]
Exception received by: io.smallrye.mutiny.helpers.UniCallbackSubscriber.onItem(UniCallbackSubscriber.java:71)
org.opentest4j.AssertionFailedError: expected: <Hello Sita> but was: <Hello Ram>
    at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:55)
    at org.junit.jupiter.api.AssertionUtils.failNotEqual(AssertionUtils.java:62)
    at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:182)
    at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:177)
    at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:1124)
...

Solution

  • There are several approaches. You can use the utility methods provided in smallrye.io/smallrye-mutiny/guides/testing. However, if, according to your comment, you need more, I would recommend the following approach:

    final Uni<Greeting> casePass = hello("Ram");
    Greeting g = casePAss.await().atMost(Duration.ofSeconds(5)); // To be sure we don't stay tucked
    // Assertions come here
    

    So basically, you block until the item is sent. Avoid await().indefinitely() because it may block your test if the Uni never send an item. Not that await()... throws an exception if the Uni sends a failure.