【问题标题】:Mock java.lang.Runtime with PowerMockito使用 PowerMockito 模拟 java.lang.Runtime
【发布时间】:2014-06-04 13:45:59
【问题描述】:

想为类似的方法编写单元测试

public static void startProgram() {
    process = Runtime.getRuntime().exec(command, null, file);
}

出于某些原因,我不想注入运行时对象,所以我想对 getRuntime 方法进行存根,它返回一个运行时模拟...我这样尝试过:

@RunWith(PowerMockRunner.class)
@PrepareForTest(Runtime.class)
public class ProgramTest {

    @Test
    public void testStartProgram() {
        Runtime mockedRuntime = PowerMockito.mock(Runtime.class);

        PowerMockito.mockStatic(Runtime.class);
        Mockito.when(Runtime.getRuntime()).thenReturn(mockedRuntime);

        ... //test
    }
}

但这不起作用。实际上似乎没有什么被嘲笑的。在测试中使用了正常的 Runtime 对象。

有人知道为什么这不起作用和/或它是如何工作的吗?

由于这个迷你示例似乎无法重现问题,这里是完整的测试代码: 测试方法(缩短)

public static synchronized long startProgram(String workspace) {
    // Here happens someting with Settings which is mocked properly
    File file = new File(workspace);
    try {
        process = Runtime.getRuntime().exec(command, null, file);
    } catch (IOException e) {
        throw e;
    }
    return 0L;
}

和测试:

@Test
public void testStartProgram() {
    PowerMockito.mockStatic(Settings.class);
    Mockito.when(Settings.get("timeout")).thenReturn("42");

    Runtime mockedRuntime = Mockito.mock(Runtime.class);
    // Runtime mockedRuntime = PowerMockito.mock(Runtime.class); - no difference
    Process mockedProcess = Mockito.mock(Process.class);

    Mockito.when(mockedRuntime.exec(Mockito.any(String[].class), Mockito.any(String[].class),
                    Mockito.any(File.class))).thenReturn(mockedProcess);

    PowerMockito.mockStatic(Runtime.class);
    Mockito.when(Runtime.getRuntime()).thenReturn(mockedRuntime);

    startProgram("doesnt matter");
}

然后,在测试中,对 Runtime.getRuntime() 的调用不会带来模拟,这就是抛出 IOException 的原因,因为 String 不是目录...

【问题讨论】:

  • 您的示例使用Mockito 1.9.5 和Powermock 1.5 对我来说效果很好。你用的是什么版本?
  • Mockito 1.9.5 & PowerMock 1.5.4
  • 同样的事情。您能否发布您的课程和测试的完整代码?
  • 我添加了我要测试的方法的缩短版本和几乎完整的测试方法版本

标签: java junit mockito powermock


【解决方案1】:

我在 cmets 上的不好,抱歉,我有一个内部类的测试,这就是为什么我没有遇到麻烦。然后我意识到这一点并看到您的@PrepareForTest(Runtime.class) 应该是@PrepareForTest(MyClass.class)(用您拥有的任何名称替换MyClass),因为Runtime 是一个系统类。您可以阅读更多关于此here 的信息并找到更多示例here。

【讨论】:

  • 但是我必须用这个注释准备的是类,我想用 PowerMock 模拟(并且不能用 Mockito 模拟)。而这里我想从 Runtime 类中模拟静态方法 getRuntime,所以我必须准备 Runtime 类。还是我错了???
  • 通常是的,除了系统类,当你必须准备调用类时。我已将回复中的 URL 更正为指向有关此特定案例的文档。
【解决方案2】:

您必须为Runtime 编写一个包装类,因为它是系统类。

public class AppShell {
  public Process exec(String command) {
    return Runtime.getRuntime().exec(command);
  }
}

然后在单元测试中,使用@PrepareForTest(AppShell.class) 而不是@PrepareForTest(Runtime.class)

@RunWith(PowerMockRunner.class)
@PrepareForTest(AppShell.class)
public class AppShellTest {

    @Mock private Runtime mockRuntime;

    @Test
    public void test() {
        PowerMockito.mockStatic(Runtime.class);

        when(Runtime.getRuntime()).thenReturn(mockRuntime);
        when(mockRuntime.exec()).thenReturn("whatever you want");

        // do the rest of your test
    }
}

见PowerMock - Mocking system classes

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-04-30
    • 2020-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多