1

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?

Allan Juan
  • 2,048
  • 1
  • 18
  • 42
  • Are you trying to do a Unit Test or an Integration Test. Is the code you're testing actually from the library/dependency you're using or are you testing your own code? – acarlstein Jan 25 '23 at 19:51
  • `service.reprocessAll()` is a method that I own and that was already tested. So I want to test `execute()` method behavior, in other words, checking that `log.info` and `log.severe` are called on the right scenarios. – Allan Juan Jan 25 '23 at 19:58
  • Ok. So, you have a few options to your disposition. One option is to 'Mock' or 'Stub' your class, then use 'Verify' to check that some things are being called. When you 'Mock' or 'Stub', you can indicate to check what are the parameters you are expecting and mock the result the methods would return. – acarlstein Jan 25 '23 at 20:06
  • Hm... I was mocking `reprocessAll` to return an `Uni`. But now you gave me the idea to mock the `Uni` instance itself, so I could try to remove the asynchronous nature from the test. I'm gonna give this is a shot. – Allan Juan Jan 25 '23 at 20:12

1 Answers1

1

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.

tmarwen
  • 15,750
  • 5
  • 43
  • 62