Hot questions for Using RxJava 2 in junit5

Question:

Job of my Vert.x server, when it gets some invalid requests, is to NOT send any resposne back, but only increase associated metric. How can I test it?

The following code don't work, because as we never get the response back, the handler's code never is executed - I've just posted it to show you what I want in my test.

@Test
void invalidUrlTest(Vertx vertx, VertxTestContext testContext) {
    HttpRequest<String> request = WebClient
            .create(vertx, this.webClientOptions)
            .get(8080, "localhost", "/someinvalidaddress/")
            .as(BodyCodec.string());
    request.send(s -> {assertThat(meterRegistry.counter("invalid.request.counter")).isEqualTo(1.0);
            });

Answer:

Not sure why your handle is not called (maybe your test is falling trough due missing ctx.async() ?) But in any case you can try to use the httpClient for your call and set an exceptionhandler when you make your assertion:

@Test
void invalidUrlTest(Vertx vertx, VertxTestContext ctx) {
    Async async = ctx.async();
    HttpClient client = vertx.createHttpClient();
    client.get(8080,"localhost","/someinvalidaddress/")
      .exceptionHandler(ex -> {
        assertThat(meterRegistry.counter("invalid.request.counter")).isEqualTo(1.0);
        async.complete();
      }).end();
}

Question:

I have a method in a class I need to test. The method uses an external class that I need to mock, so the external class doesn't get tested or executes its dependencies. The special challenge is: one method of the external class gets overridden. Method looks like this:

public void fetchLocalData(final String source, final ObservableEmitter<String> destination) {
   final List<String> options = Arrays.asList("recursive","allFiles","includeDir");
   // This class comes from a package
   final DirScan dirscan = new DirScan(source, options) {
       @Override
       protected Action getResult(final String result) {
           destination.onNext(result);
           return Action.Continue;
       }
   };
   dirscan.scan();
   destination.onComplete();
}

I tried:

    DirScan scanner = mock(DirScan.class);
    when(scanner.scan()).thenReturn("one").thenReturn("two");

That didn't work. What do I miss? How would I need to refactor to make this testable?


Answer:

If you want to replace the dirscan with a mock (or a spy) you'll need to refactor your class that it's a dependency or parameter. Alternatively you could use PowerMockito's whenNew functionality.

Lets assume you change your class and instead of the String source you provide the DirScan object as a parameter. You would need to have some kind of creation method for dirscan elsewhere (might be a static method).

final List<String> options = Arrays.asList("recursive","allFiles","includeDir");

public DirScan createDirScan(String source) {

   // This class comes from a package
   final DirScan dirscan = new DirScan(source, options) {
       @Override
       protected Action getResult(final String result) {
           destination.onNext(result);
           return Action.Continue;
       }
   };

   return dirscan;
}
public void fetchLocalData(final DirScan dirscan, final ObservableEmitter<String> destination) {
    dirscan.scan();
    destination.onComplete();
}

Juding from your question you seem to want to test the interaction with the destination object, so you do not want to mock the dirscan object (because if you do there won't be any interaction). You might want to use a spy and only replace the getResult method.

In your test now you could then simply pass a spy for the dirscan object and define the behaviour of it with thenAnswer.

final ObservableEmitter<String> destination = ...

DirScan dirscan = Mockito.spy(createDirScan(source, destination));

Mockito.when(dirscan.getResult(Mockito.any(String.class))).thenAnswer((Answer<Action>) invocation -> {
    String result = invocation.getArgument(0);
    destination.onNext(result);

    return Action.Continue;
});

classUnderTest.fetchLocalData(dirscan, destination);

At this point you might notice that its probably better to not use a spy and just use the real DirScan object. Using the spy to do what you intend to do with the overriden method looks like overkill to me.

The real object has to work for this test to be of value, so you might as well test the real thing.