2

I am writing unit tests for one of our reactive methods. This method depends on another service. I have mocked this service. While running the test, i am getting the below error: java.lang.AssertionError: expectation "expectError(Class)" failed (expected: onError(MyException); actual: onComplete()).
Here is what I have tried:
Method(ReactiveService.class):

@Autowired
private Service serice;

public Mono<MyObject> save(List<MyObject> arg1, String arg2) {
    return SomeUtil.user()
            .map(user -> service.save(arg1, arg2, user))
            .subscribeOn(scheduler)
            .doOnError(e -> {
                throw new MyException(MyObject.class, "save object", e);
            });
}

Test:

@Mock
Service service;

@InjectMocks
ReactiveService reactiveService;

@Test
public void unit_test(){
    when(service.save(any(), any(), any())).thenThrow(new RuntimeException());
    Mono<MyObject> result = reactiveService.save(arg1, arg2);
    StepVerifier.create(result)
        .expectError(MyException.class)
        .verify();
}

From the error I understood that, no signal is received from the method. But I am not getting what I have missed here.

Rozart
  • 1,668
  • 14
  • 27
Antony Vimal Raj
  • 364
  • 3
  • 14
  • What have you done to resolve it? What have you analyzed? What were the results? What exactly is not clear? – mentallurg Oct 06 '19 at 16:37
  • @mentallurg The previous version of code was having `Mono.defer()` where the junit worked fine. Now after adding the `user` and `map` function it is not working. I suspect that the mocked method is not getting invoked during execution. – Antony Vimal Raj Oct 06 '19 at 20:38
  • You can easily check, if the mocked method is invocked: call it in the method save() directly. Then you will see if there is an exception. After check you can remove it again. – mentallurg Oct 06 '19 at 21:26
  • your service name is `serice` – Toerktumlare Oct 06 '19 at 23:01
  • @Rozart Its correct only. I am testing `ReactiveService` class which depends on `Service` class. So i have mocked `Service` class. I am suspecting the `Mono.map()` method, will mock methods get invoked from `map`? – Antony Vimal Raj Oct 07 '19 at 12:51

1 Answers1

1

I think that the issue you have is caused by SomeUtil.user() not emitting a value.

Why do I think it's the case: I have tried out a simple example to reproduce your issue:

    @Test
    void test() {
        Mono<String> monoWithContent =
            Mono.just("Content")
            .map(element -> exceptionThrower());

        // TEST 1
        StepVerifier.create(monoWithContent)
            .expectError()
            .verify();

        Mono<String> monoWithoutContent =
            Mono.empty()
            .map(element -> exceptionThrower());

        // TEST 2
        StepVerifier.create(monoWithoutContent)
            .expectError()
            .verify();
    }

    String exceptionThrower() {
        throw new RuntimeException();
    }

The result is :

TEST 1 - passes successfully, because the value is emitted from Mono and it is mapped to an exception (the RuntimeException thrown by the exceptionThrower().

TEST 2 - fails, because there is no value to be emitted from Mono, so the map method is not invoked and the whole execution finishes without an error.

So to summarize, if there is no content emitted from the Publisher, then the transformation operations are not invoked.

Rozart
  • 1,668
  • 14
  • 27
  • 1
    Got it! So I need to mock `SomeUtil.user()` as well to emit some value. – Antony Vimal Raj Oct 07 '19 at 13:24
  • Yes sure. Actually I am executing the tests now. The issue I am facing is `SomeUtil.user()` is a static method which i am not able to mock using mockito. – Antony Vimal Raj Oct 07 '19 at 14:14
  • This is a different topic. But in general you should either use PowerMock ( https://stackoverflow.com/a/21116014/1506009 ) or better, refactor your code not to use a static method in this context. – Rozart Oct 07 '19 at 14:16