0

Trying to write a test that will call my method, when that method makes a call to another method we will throw a custom exception i have made. Here i have simplified it all

2 functions

public MyJsonResponse hello() {
        MyJsonResponse response = new MyJsonResponse();
        response.setErrorMessage("1");
        response.setStatus("some status");
        response.setData("1");
        response.setHttpResponse(200);
        try{
            hi();
            return response;
        }catch (MyServiceException e) {
            response.setErrorMessage(e.getMessage());
            response.setStatus("error creating");
            response.setData("2");
            response.setHttpResponse(e.getResponseStatus());
            return response;
        }

    }

    public String hi() throws  MyServiceException{
        LOG.error("Exception");
        return "yea";
    }

The test I have written is this

    @Test
    public void myTest() throws Exception {

        given(service.hi()).willAnswer( invocation -> { throw new MyServiceException("abc msg",511); });
        MyJsonResponse actual = service.hello();

        Assert.assertNotNull(actual);
        assertEquals(511, actual.getHttpResponse());
    }

But unfortunately the result is as follows

java.lang.AssertionError: 
Expected :511
Actual   :200
AnonymousAlias
  • 1,149
  • 2
  • 27
  • 68
  • 1
    Not familiar with the BDD style of Mockito but are you sure that the exception is actually being thrown and handled? Have you tried debugged the test case and/or just used some simple tracing statements to check? – stridecolossus Jun 03 '21 at 14:16
  • Yea I've debugged, it's not being thrown and handled. I am trying to figure out why that is. Also open to alternative ways of testing this. – AnonymousAlias Jun 03 '21 at 14:17
  • The `given` clause does look suspicious, should perhaps be `willThrow(new MyServiceException(...)).given(service).hi()` or something like that? – stridecolossus Jun 03 '21 at 14:21
  • Tried that but got - Checked exception is invalid for this method! – AnonymousAlias Jun 03 '21 at 14:23
  • Ah hadn't noticed the `hi` method is a member of the class under test, I'd assumed it was a separate service. Presumably you create a *concrete* instance of `service` in the setup/before method of your test, so you can't stub that method (not without using nasty partial spy mocks anyway). Easier to extend the service class and override the `hi` method rather than mocking it? – stridecolossus Jun 03 '21 at 14:31
  • Don't really want to make change to the service just need to write a test for the way it is if that makes sense. – AnonymousAlias Jun 03 '21 at 15:10
  • What does your `hi()` method *really* do? Currently it just logs something and returns a string. Is there any method invocation of a dependency in your `hi()` method which you can mock and let them throw an exception? Your test fails because your `service` is not a mock and therefore you can not set any mocked behaviour. – Daniel Rafael Wosch Jun 08 '21 at 09:53
  • Otherwise you should try to spy your service: `var serviceSpy = Mockito.spy(service);` `willThrow(new MyServiceException("abc msg",511)).given(serviceSpy).hi();` – Daniel Rafael Wosch Jun 08 '21 at 09:56
  • The real method that hi represents does a lot I was thinking it would be easier to avoid mocking a lot of the calls and methods in there – AnonymousAlias Jun 08 '21 at 10:03
  • Have you tried the `spy` approach? Otherwise why not mocking the internals of your `hi()` method? E.g. if `hi()` relies on a dependency which you can mock, inject in your service and mock the method which results in an exception? – Daniel Rafael Wosch Jun 08 '21 at 10:07
  • Are you sure you are calling `hello()` real implementation, and not an empty mock ? How is `service` instanciated ? – Florent Bayle Jun 08 '21 at 12:21

3 Answers3

0

regarding what you explain and what your code look like, I am not sure if I have well understood. Thus, if you want that, your hi() : function throws an exception. You have to make it first throws an exception. Take a look at code below!

 public String hi() throws  MyServiceException{
        /*LOG.error("Exception");//No don't just log, throw a real exception as below*/
       throw new MyServiceException("text here, if your constructor support it or nothing otherwise")
     /*return "yea";//Nothing to return? we have just break the code by throwing the exception above*/
    }

After that, please be very sure that your 'MyServiceException.getHttpResponse()' will really return 511

Toukea Tatsi
  • 189
  • 1
  • 5
0

Please, be sure that you are using a spy as you want to use the actual code for some methods of your mocked service and just stubbing specific methods of it. Please, see for instance this related SO question about the subject.

Also, consider modifying your test definition to use willThrow instead of willAnswer: as pointed out by @eis, you can still use the later, but the former is more straightforward.

Your code will look similar to this:

@Test
public void myTest() throws Exception {
  MyService service = spy(MyService.class);

  willThrow(new MyServiceException("abc msg",511))
    .given(service)
    .hi()
  ;

  // As pointed out by @eis, you can still use willAnswer
  // willAnswer(
  //   invocation -> { throw new MyServiceException("abc msg",511);}
  // )
  //   .given(service)
  //   .hi()
  // ;

  
  MyJsonResponse actual = service.hello();

  Assert.assertNotNull(actual);
  assertEquals(511, actual.getHttpResponse());
}
jccampanero
  • 50,989
  • 3
  • 20
  • 49
  • I wouldn't think willThrow vs willAnswer would make any difference in this case, even though using willThrow is more straight forward – eis Jun 08 '21 at 14:47
  • I agree with you @eis. The actual solution has to do with the use of `spy`. I will modify the answer with your feedback. Thank you very much for pointing that out. – jccampanero Jun 08 '21 at 16:01
-1

For this test to make sense, your hi() call should be done calling another service that you stub/mock in your test class. You're not doing that, so this approach won't work.

You wrote "the real method that hi represents does a lot", so it's about time you extract that to another service.

eis
  • 51,991
  • 13
  • 150
  • 199