0

I'm trying to write a unit test to test this piece of code, but I falled in Mockito/Powermockito limits with native class java.lang.Class as explained here.

How could I test this:

Method[] serverStatusMethods = serverStatus.getClass().getMethods();
    for (Method serverStatusMethod : serverStatusMethods) {
        if (serverStatusMethod.getName().equalsIgnoreCase("get" + field)) {
            serverStatusMethod.setAccessible(true);
            try {
                Number value = (Number) serverStatusMethod.invoke(serverStatus);
                response = new DataResponse(field + " value", value);
            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
                Logger.getLogger(StatusServlet.class.getName()).log(Level.SEVERE, null, ex);
                response = new ErrorResponse(HttpStatus.Code.INTERNAL_SERVER_ERROR, ex);
            }
            break;
        }
    }

to throw this exceptions intentionally in test case:

catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
            Logger.getLogger(StatusServlet.class.getName()).log(Level.SEVERE, null, ex);
            response = new ErrorResponse(HttpStatus.Code.INTERNAL_SERVER_ERROR, ex);
}
Frighi
  • 475
  • 4
  • 17

1 Answers1

2

Do what you do whenever mocking a class is too difficult: add another layer of abstraction. E.g. extract the reflective operations into a separate method:

public Number resolveServerStatus(Object serverStatus)
    throws IllegalAccessException, IllegalArgumentException,
        InvocationTargetException {

    Method[] serverStatusMethods = serverStatus.getClass().getMethods();
    for (Method serverStatusMethod : serverStatusMethods) {
        if (serverStatusMethod.getName().equalsIgnoreCase("get" + field)) {
            serverStatusMethod.setAccessible(true);
            return (Number) serverStatusMethod.invoke(serverStatus);
        }
    }
}

Now mock the resolveServerStatus method.

This is what you should have done in the first place if you had followed the single responsibility principle. Your method had two responsibilities: resolving the status number and converting it to DataResponse object. The multiple responsibilities made testing the method dififficult.

Torben
  • 3,805
  • 26
  • 31
  • Thanks for answering, you are right I did not followed correctly the "single responsibility principle". But with your solution I just move the problem in another layer. I cannot throw the exception from `invoke(serverStatus)` method anyway. – Frighi Jan 15 '20 at 14:33
  • 1
    You're not interested in throwing an exception from the invoke method. You're interested in throwing an exception from resolveServerStatus and verifying that your code behaves expectedly. You can accept that some things are too complicated and low value to spend a lot of time on (unless of course you're doing code coverage percentage because of bureaucratic reasons :)). – Torben Jan 15 '20 at 20:19
  • Ok thanks for help, I always feel like the code could be broken if the coverage is not high, but for this difficult cases I think the test could be ignored without problems. I solved as you advice, applying the SRP. – Frighi Jan 16 '20 at 11:27