0

I have the following service and test methods and I am trying the code execute catch (ApplicationException e) { } block.

public abstract class ApplicationException extends RuntimeException {
    // ....
}
public void create(Request request) {
    
    try {
        // ...
    } catch (ApplicationException e) {
        // I want the code hits this block and check the values in here
    } 
}

Here is the test method:

@InjectMocks
private ProductServiceImpl productService;


@Test
public void test() {

    // variable defnitions and stubbings (code omitted)

    willAnswer( invocation -> { throw new RuntimeException("abc msg"); })
        .given(productService).create(request);

    // or
    // doThrow(new RuntimeException()).when(productService).create(request);


    // service method call
    productService.create(Request request);
}

When I debug the code, I get error on doThrow line:

org.mockito.exceptions.misusing.NotAMockException: Argument passed to when() is not a mock!

So, how can I solve the problem?

  • Use "@Mock" on your productService dependency and "@InjectMocks" as a clans annotation. "@InjectMock" creates mock classes for All dependencies annotated with "@Mock". – The Frozen One Apr 12 '22 at 11:01
  • `productService` is not a mock, it's the thing that you are testing (you are injecting mocks into it by using `@InjectMocks` on it). So it's not a thing that you should pass to Mockito's `when(...)` method, as you are doing in the commented out line. – Jesper Apr 12 '22 at 11:02
  • @TheFrozenOne Yes Amigo, you are right thanks. However, this time I cannot make the code hits inside that catch block. Is there anything that I am missing? –  Apr 12 '22 at 11:10
  • @Casper Yes, how should I use it properly and hit the code inside catch block? –  Apr 12 '22 at 11:12

1 Answers1

0

As @Jesper mentioned in comment you are not using Mockito properly.

For your test case you need to test that your ProductService.create method will handle an error in a given scenario. Let's imagine that your code looks like this.

class ProductService {
    private SomeOtherService someOtherService;
    
    public void create(Request request) {
    
    try {
        someOtherService.execute();    
    } catch (ApplicationException e) {
        // I want the code hits this block and check the values in here
enter code here
        throw new MyException(e); // Here you can do something else
    } 
}

So someOtherService.execute can throw ApplicationException. We need to test if our ProductService.create will catch that exception and do some processing. In the example we will just throw a different type of exception.

@Mock
private SomeOtherService mockOtherService;
@InjectMocks
private ProductServiceImpl productService;


@Test
public void test() {
  
   doThrow(new ApplicationException()).when(someOtherService).execute();
    
   given(productService.create(request)).willThrow(new MyException());
}

So main difference from your example is that we are telling the SomeOtherService mock what it should do when execute method is called. This is allowed and Mockito knows how to work with mocks.

In your example you were trying to pass a real object not a mock. @InjectMock annotation is a shorthand for this

this.productService = new ProductService(mockSomeOtherService);

So it creates a new object with its dependency mocked. More about this you can find here https://stackoverflow.com/a/16467893/2381415.

I didn't run this code or test it so do not C/P it.

Hope it helps you understand what was wrong with your approach.

Bruno
  • 89
  • 4
  • Thank you so much for your wonderful explanations. Actually, I can hit inside that block if I use `doThrow(new RuntimeException()).when(...)`. Why I tried it, because `ApplicationException` is an abstract class and even I try to use it as `doThrow(ApplicationException.class).when(...)`. So, how can I catch `ApplicationException`? –  Apr 12 '22 at 12:02
  • I fixed the problem by mocking my abstract class as `doThrow(Mockito.mock(ApplicationException.class)).when(productService).create(any());` as mentioned on [here](https://stackoverflow.com/questions/16252171/is-it-possible-to-throw-an-abstract-exception-using-mockito). Thanks a lot for your help. –  Apr 12 '22 at 12:36
  • I will mark your answer after you add necessary note regarding to mocking abstract exception mentioned my previous comment. –  Apr 12 '22 at 12:37
  • You could use one of the implementations of ApplicationException abstract class in the throw. I am not sure what those implementation are ... but catch will catch any exception that has ApplicationException inherited. – Bruno Apr 12 '22 at 13:34
  • 1
    But it just could catch `RuntimeException` and that's why I use the approach mentioned on https://stackoverflow.com/questions/16252171/is-it-possible-to-throw-an-abstract-exception-using-mockito –  Apr 12 '22 at 14:24