如何使用 PowerMockito 模拟 System.exit?
How to mock System.exit with PowerMockito?
我想对调用 System.exit(-1) 的代码 Java 进行单元测试,并希望它不执行任何操作而不是退出进程。根本原因是 JaCoCo 无法正常工作,项目指南希望看到该行被覆盖。更改经过测试的代码也不是一种选择。对系统的其他调用应该正常工作。 PowerMockito 2.0.7 已经在项目中使用,这里也应该使用。我当前的 Java 版本是 Windows.
上的 1.8.0_181
我试过
PowerMockito.spy(System.class);
PowerMockito.doNothing().when(System.class, "exit", ArgumentMatchers.any(int.class));
//here comes the code under test that calls System.exit
好像不行,System.exit好像还是退出了进程。
它是如何工作的?
我认为您应该替换示例代码中的两行
PowerMockito.spy(System.class);
PowerMockito.doNothing.....
到
PowerMockito.mockStatic(System.class);
此更改在我的本地有效,因为 System.exit 由于静态方法上的 mock 不执行任何操作。
此外,我希望您正在使用 PrepareForTest 注释
@PrepareForTest(CLASS_UNDER_TEST)
间谍方法是调用真正的方法并对非静态方法进行一些包装。由于您需要模拟静态方法,因此应改用 mockStatic 方法。
更新 1
PowerMockito mockStatic 方法默认为 class 中的所有静态方法创建 mock。我没有任何干净的解决方案。但是,我可以建议一个看起来丑陋但可以满足需要的解决方案,即仅模拟特定的静态方法,其余方法调用真实方法。 PoweMockito 的 mockStatic 方法在内部调用 DefaultMockCreator 来模拟静态方法。
@RunWith(PowerMockRunner.class)
public class StaticTest {
@Test
public void testMethod() throws Exception {
// Get static methods for which mock is needed
Method exitMethod = System.class.getMethod("exit", int.class);
Method[] methodsToMock = new Method[] {exitMethod};
// Create mock for only those static methods
DefaultMockCreator.mock(System.class, true, false, null, null, methodsToMock);
System.exit(-1); // This will be mocked
System.out.println(System.currentTimeMillis()); // This will call up real methods
}
}
根据 PowerMockito 文档,调用 static void 方法的正确方法是 -
PowerMockito.mockStatic(SomeClass.class);
PowerMockito.doNothing().when(SomeClass.class);
SomeClass.someVoidMethod();
这应该为特定的静态 void 方法创建模拟行为。不幸的是,这对 System Class 不起作用,因为 System class 是最终的。如果它不是最终的,这会奏效。我试过了,我得到了这个异常 -
org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class java.lang.System
Mockito cannot mock/spy because :
- final class
代码-
@Test
public void testMethod() throws Exception {
PowerMockito.mockStatic(System.class);
PowerMockito.doNothing().when(System.class);
System.exit(-1); // mockito error coming here
System.exit(-1);
System.currentTimeMillis();
}
我想对调用 System.exit(-1) 的代码 Java 进行单元测试,并希望它不执行任何操作而不是退出进程。根本原因是 JaCoCo 无法正常工作,项目指南希望看到该行被覆盖。更改经过测试的代码也不是一种选择。对系统的其他调用应该正常工作。 PowerMockito 2.0.7 已经在项目中使用,这里也应该使用。我当前的 Java 版本是 Windows.
上的 1.8.0_181我试过
PowerMockito.spy(System.class);
PowerMockito.doNothing().when(System.class, "exit", ArgumentMatchers.any(int.class));
//here comes the code under test that calls System.exit
好像不行,System.exit好像还是退出了进程。 它是如何工作的?
我认为您应该替换示例代码中的两行
PowerMockito.spy(System.class);
PowerMockito.doNothing.....
到
PowerMockito.mockStatic(System.class);
此更改在我的本地有效,因为 System.exit 由于静态方法上的 mock 不执行任何操作。
此外,我希望您正在使用 PrepareForTest 注释
@PrepareForTest(CLASS_UNDER_TEST)
间谍方法是调用真正的方法并对非静态方法进行一些包装。由于您需要模拟静态方法,因此应改用 mockStatic 方法。
更新 1
PowerMockito mockStatic 方法默认为 class 中的所有静态方法创建 mock。我没有任何干净的解决方案。但是,我可以建议一个看起来丑陋但可以满足需要的解决方案,即仅模拟特定的静态方法,其余方法调用真实方法。 PoweMockito 的 mockStatic 方法在内部调用 DefaultMockCreator 来模拟静态方法。
@RunWith(PowerMockRunner.class)
public class StaticTest {
@Test
public void testMethod() throws Exception {
// Get static methods for which mock is needed
Method exitMethod = System.class.getMethod("exit", int.class);
Method[] methodsToMock = new Method[] {exitMethod};
// Create mock for only those static methods
DefaultMockCreator.mock(System.class, true, false, null, null, methodsToMock);
System.exit(-1); // This will be mocked
System.out.println(System.currentTimeMillis()); // This will call up real methods
}
}
根据 PowerMockito 文档,调用 static void 方法的正确方法是 -
PowerMockito.mockStatic(SomeClass.class);
PowerMockito.doNothing().when(SomeClass.class);
SomeClass.someVoidMethod();
这应该为特定的静态 void 方法创建模拟行为。不幸的是,这对 System Class 不起作用,因为 System class 是最终的。如果它不是最终的,这会奏效。我试过了,我得到了这个异常 -
org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class java.lang.System
Mockito cannot mock/spy because :
- final class
代码-
@Test
public void testMethod() throws Exception {
PowerMockito.mockStatic(System.class);
PowerMockito.doNothing().when(System.class);
System.exit(-1); // mockito error coming here
System.exit(-1);
System.currentTimeMillis();
}