Allan Juan
Allan Juan

Reputation: 2554

How to test code that subscribes to an Uni?

I know that I can test a method that returns an Uni:

@Test
public void testUni() {
  service.doSomething().invoke(data -> {
    // run assertions
  }).subscribe().withSubscriber(UniAssertSubscriber.create()).assertCompleted();
}

But what if I want to test the method that subscribes to the Uni itself? For example, consider this piece of code:

public void execute() {
  service.reprocessAll().subscribe().with(
    success -> log.info("Reprocessing ran successfully."),
    error -> log.severe("Reprocessing failed: " + error.getMessage())
  );
}

If I try to test it like this...

@Test
public void shouldLogSuccessAfterReprocessing() {
  service.execute()

  Mockito.verify(log, times(1)).success("Reprocessing ran successfully");
}

The test will fail due to a race condition. I mean, the test code will run before the actual code under test (the log.success call). So how can I tell the test to wait for the Uni to complete? Or how could I refactor this to make it testable?

Upvotes: 1

Views: 394

Answers (1)

tmarwen
tmarwen

Reputation: 16354

The proper question would be how to design the code so that it is unit-testable which may lead a different answer than the one I will be writing here to respond to your current need.

Since the service#reprocessAll computation will be triggered on the background, and you have no means of controlling it behavior as your #service method simply returns void, you can block the calling unit runtime thread awaiting for the processing to finish:

@Test
public void shouldLogSuccessAfterReprocessing() throws Exception {
  service.execute()
  Thread.sleep(1000); // wait for reprocessAll to finish then proceed with assertions
  Mockito.verify(log, times(1)).success("Reprocessing ran successfully");
}

For finer control, you can use the awaitiliy library for condition testing.

Upvotes: 1

Related Questions