【问题标题】:Cannot unit test Java code uses reflection with Mockito nor PowerMockito无法对 Java 代码使用反射与 Mockito 或 PowerMockito 进行单元测试
【发布时间】:2020-01-15 11:20:06
【问题描述】:

我正在尝试编写一个单元测试来测试这段代码,但是正如 here 所解释的那样,我使用原生类 java.lang.Class 陷入了 Mockito/Powermockito 限制。

我该如何测试:

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;
        }
    }

在测试用例中故意抛出这个异常:

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

【问题讨论】:

    标签: java unit-testing reflection mockito powermockito


    【解决方案1】:

    当模拟一个类太困难时,做你做的事情:添加另一个抽象层。例如。将反射操作提取到一个单独的方法中:

    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);
            }
        }
    }
    

    现在模拟resolveServerStatus 方法。

    如果您关注了single responsibility principle,这就是您首先应该做的事情。您的方法有两个职责:解析状态编号并将其转换为DataResponse 对象。多重职责使测试方法变得困难。

    【讨论】:

    • 感谢您的回答,您说得对,我没有正确遵循“单一责任原则”。但是通过您的解决方案,我只是将问题移到了另一层。我无论如何都不能从invoke(serverStatus) 方法中抛出异常。
    • 您对从调用方法抛出异常不感兴趣。您有兴趣从 resolveServerStatus 引发异常并验证您的代码是否符合预期。您可以接受有些事情太复杂且价值太低而无法花费大量时间(当然,除非您因为官僚原因而在做代码覆盖率 :))。
    • 好的,感谢帮助,我总觉得如果覆盖率不高,代码可能会被破坏,但是对于这种困难的情况,我认为可以忽略测试而不会出现问题。我按照你的建议解决了,应用了 SRP。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-19
    • 1970-01-01
    • 2017-11-22
    • 1970-01-01
    相关资源
    最近更新 更多