如何使用PowerMockito模拟System.exit?

时间:2020-08-01 10:42:34

标签: java mocking mockito powermockito

我想对调用System.exit(-1)的Java代码进行单元测试,并希望它不执行任何操作而不退出该进程。根本原因是,否则JaCoCo无法正常工作,并且项目准则希望看到该行。更改测试代码也不是一种选择。对System的其他调用应正常工作。 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似乎仍然退出了该进程。 如何使它工作?

1 个答案:

答案 0 :(得分:1)

我认为您应该替换示例代码中的两行

PowerMockito.spy(System.class);
PowerMockito.doNothing.....

PowerMockito.mockStatic(System.class);

此更改在我的本地系统中有效,因为System.exit由于对静态方法进行模拟而没有执行任何操作。

此外,我希望您使用的是PrepareForTest批注

@PrepareForTest(CLASS_UNDER_TEST)

spy方法是调用真实方法,并在非静态方法周围有一些包装。由于您需要为静态方法提供模拟,因此应改为使用模拟静态方法。

更新1

默认情况下,PowerMockito mockStatic方法为类中的所有静态方法创建模拟。我没有任何干净的解决方案。但是,我可以建议一个看起来丑陋但可以满足需要的解决方案,即仅模拟特定的静态方法而其余方法正在调用实际方法。 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文档,调用静态void方法的正确方法是-

PowerMockito.mockStatic(SomeClass.class);
PowerMockito.doNothing().when(SomeClass.class);
SomeClass.someVoidMethod();

参考-https://github.com/powermock/powermock/wiki/Mockito#how-to-stub-void-static-method-to-throw-exception

这应该为特定的静态void方法创建模拟行为。不幸的是,这不适用于系统类,因为系统类是最终的。如果不是最终的话,那将会奏效。我尝试了,但遇到了这个例外-

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