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

我遇到了一个使用JMockit(1.21)模拟java.lang.Math的问题。 请参阅下面的实际课程的简化用法。 基本上在我的代码中的某个地方我使用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$1 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$1 at java.net.URLClassLoader$1.run(URLClassLoader.java:372) at java.net.URLClassLoader$1.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 

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

因为1) java.lang.Math中的方法(特别是Math.min(a, b) )被JRE中的其他类一直调用(例如,查看java.lang.String ),以及2)当JMockit @Mocked一个类(无论如何都是@Mocked )时,它会在测试期间被@Mocked ,无论调用来自何处

最重要的是,除非你真的知道自己在做什么,否则不要模仿低级别的JRE课程。 在这种特殊情况下,JMockit可能应该否认java.lang.Math的完全模拟,因为实际上没有充分的理由(我可以看到)这样做。