kane
kane

Reputation: 6017

How do you verify a Reactor operator is subscribed to when it returns nothing (and also when testing via WebTestClient)?

I have a Spring Webflux endpoint like this. Notice the .ignoreElement() and NO_CONTENT response.

interface Thing {
  Mono<String> doSomething();
}

@Autowired Thing thing1; // e.g. this writes to DB
@Autowired Thing thing2; // e.g. this writes to Disk

@ResponseStatus(HttpStatus.NO_CONTENT)
@PostMapping(path = "/do2Things")
public Mono<String> do2Things() {
  return thing1.doSomething().ignoreElement()
    .then(thing2.doSomething().ignoreElement());
}

How do I write a test to verify that both thing1 and thing2 do their thing?

Maybe something like this?

@Autowired WebTestClient webClient;

@MockBean("thing1") Thing thing1;
@MockBean("thing2") Thing thing2;


@Test
public void verifyThings() {

  webClient
    .post()
    .uri("/do2Things")
    .exchange()
    .expectStatus()
    .isNoContent();
  
  verify(thing1, times(1)).doSomething();
  verify(thing2, times(1)).doSomething();
}

This test passes.

But if someone were to make the mistake of re-implementing the endpoint like this

@ResponseStatus(HttpStatus.NO_CONTENT)
@PostMapping(path = "/do2Things")
public Mono<String> do2Things() {
  return thing1.doSomething().ignoreElement()
    .transform(ignored -> thing2.doSomething().ignoreElement());
}

Then this should fail, but my unit test still passes. This passes because thing1.doSomething() is called and returns a Mono. This should fail because thing1's Mono is never subscribed to. The developer broke the reactor chain by ignoring it.

This is exactly what happened and I want to set the pattern for the unit tests so that this is less likely to happen.

So what I want to test is whether all the Reactor operators are subscribed to. In an ideal world, I'd inspect the response but we don't return responses in some cases when they are either unnecessary or unwanted because it may expose some sensitive info back to clients.

I may be thinking about it all wrong, so open to some ideas.

Upvotes: 1

Views: 1199

Answers (1)

JEY
JEY

Reputation: 7123

You should use PublisherProbe. This will allow to assert multiple things like if it as been subscribed, requested, etc...

In your case do something like:

PublisherProbe<Void> probSomething = PublisherProbe.empty();
Mockito.when(thing1.doSomething()).thenReturn(probSomething);
/*
...
*/
probSomething.assertWasSubscribed();

Upvotes: 3

Related Questions