为什么我不能使用 JMockit 模拟 Math

Why can't I mock Math using JMockit

我 运行 遇到了使用 JMockit (1.21) 模拟 java.lang.Math 的问题。请参阅下文以简化使用我的实际 class。基本上在我的代码中某处我使用 Math.pow(...) 并且我想模拟它。

public final class Calculator {
    public final double power(double base, double exponent) {
        return Math.pow(base, exponent);
    }
}

至于我的测试代码,这个测试有效。

@Test
public void simpleTestWithoutMock() {
    Calculator calculator = new Calculator();
    double result = calculator.power(2, 3);
    assertThat(result).isEqualTo(8);
}

此测试失败。

@Test
public void simpleTestWithMock(@Mocked Math math) {
    new Expectations() {{ // This would be line 67 in below stracktrace
        Math.pow(2,3); result = 1;
    }};

    Calculator calculator = new Calculator();
    double result = calculator.power(2, 3);
    assertThat(result).isEqualTo(1);
}

我得到的错误信息:

java.lang.NoClassDefFoundError: nl/endran/sandbox/CalculatorTest

        at nl.endran.sandbox.CalculatorTest.simpleTestWithMock(CalculatorTest.java:67)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:483)
        at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
        at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
        at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:483)
        at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
        Caused by: java.lang.ClassNotFoundException: nl.endran.sandbox.CalculatorTest
        at java.net.URLClassLoader.run(URLClassLoader.java:372)
        at java.net.URLClassLoader.run(URLClassLoader.java:361)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        ... 9 more

我可以像这样模拟其他系统 classes SystemRunTime,但是 Math 似乎不起作用(String 就此而言)。我知道如何规避这是我的测试,所以我没有被阻止或任何东西,但我不明白为什么 Math 不能被嘲笑。删除 Expectations 块将不会再导致 NoClassDefFoundError 错误。我怀疑具有像 public static native 这样的签名的方法在其中发挥作用,但我找不到任何东西。

因为 1) 来自 java.lang.Math(特别是 Math.min(a, b))的方法 一直被来自 class 的其他 调用JRE(例如,查看 java.lang.String 内部),以及 2)当 JMockit 模拟 class(无论如何使用 @Mocked)时,它会在测试期间被模拟,无论 电话来自哪里

底线,除非您真的知道自己在做什么,否则不要模拟低级 JRE classes。在这种特殊情况下,JMockit 可能应该拒​​绝 java.lang.Math 的完全模拟,因为确实没有充分的理由(我可以看到)这样做。