Search code examples
javaspringjunitpowermockito

JUnit test Custom exception that throws @httpStatus


I would like to test that my custom exception is thrown when I call a method like that:

private MyObject queryDatabase(String request, String end){
    HttpEntity myEntity = new NStringEntity(request, ContentType.APPLICATION_JSON)
    Response response = restClient.performRequest("GET", end,Collections.emptyMap(), myEntity)

    MyObject myObject = mapper.readValue(response.getEntity().getContent(), MyObject.Class);
    if(myObject.getFunctions().isEmpty()){
        throw new EmptyResultException("Empty result");
    }
    return myObject;
}

My EmptyResultException Class :

@ResponseStatus(value=HttpStatus.NO_CONTENT)
public Class EmptyResultException() extends RuntimeException(){
    ...
}

I'm just starting with JUnit and I have tried :

@Mock MyService myservice;

@Test(expected=EmptyResultException.class)
public void shouldReturnException() {
    when(myService.queryDatabase(anyString(),anyString())).thenReturn(new MyObject());
}

It's not working. The behavior I want to try is in private method. It seems I should use Powermock for such cases. However, I have read it is not good to test private method so I would like to change my method to public. Any help please?

EDIT : My full implementation :

I have a Restcontroller :

@RestController
@RequestMapping...
public class MyController {

    @Autowired 
    MyService myService;

    @RequestMapping...
    public MyObject findObject(@Valid DtoParameters parameters){
      return myService.executeQuery(parameters);
   }
   }

And in myService Class :

@Service
public class MyService{

public MyObject executeQuery(DtoParameters parameters){
 return 
    queryDatabase(parameters.buildRequest(),parameters.buildEnd());

}
}

Solution

  • If your class under test is MyService, it shouldn't have a @Mock.

    I don't know your whole implementation, but let's assume MyService have injected dependencies (like your mapper)

    First I would mock the mapper and inject it in MyService:

    @Mock
    private ObjectMapper mapper;
    
    @InjectMocks
    private MyService myService;
    

    For this to work, your test class need to use the mockito runner. You can annotate your class with this:

    @RunWith(MockitoJUnitRunner.class)
    

    The mocks will be injected into MyService. Now you can mock your mapper to return an empty object:

    when(mapper.readValue(any(),any())).thenReturn(new MyObject());
    myService.queryDatabase("request", "end")
    

    when calling queryDatabase, this should call the mock inside.

    If you were trying to test your rest controller, it is a different way. What I suggested is a unit test on MyService. If you want to test the controller, you should do it with a SpringRunner, SpringBootTest and MockMvc. But first, unit test your service, and add other tests on your controller later. For the controller, you would annotate MyService with @MockBean and throw, or Autowire it and @MockBean the mapper inside to return an empty object like the unit test.

    Check this: https://spring.io/guides/gs/testing-web/


    old answer:

    You could change your method to protected, assuming your test is in the same package as the class you are testing, you will be able to mock it.

    To mock your method, you need to write it like this:

    when(myService.queryDatabase(anyString(),anyString())).thenThrow(EmptyResultException.class);
    

    You forgot to use the when method to wrap your call.