Java Runtime.getRuntime().exec jUnit测试

Java Runtime.getRuntime().exec jUnit测试,java,unit-testing,Java,Unit Testing,我有一个类,在它的一些方法中使用 Runtime.getRuntime().exec ... 例如: public class MyClass { public void doSomething() { ...do something... Runtime.getRuntime().exec ... ...do something else } } 不幸的是,由于一些需求,我“无法重构”这个类。我想在这个类上创建jUnit测试,

我有一个类,在它的一些方法中使用

Runtime.getRuntime().exec ...
例如:

public class MyClass {
    public void doSomething() {
        ...do something...
        Runtime.getRuntime().exec ...
        ...do something else
    }
}
不幸的是,由于一些需求,我“无法重构”这个类。我想在这个类上创建jUnit测试,我发现很难模拟运行时类


假设我想在运行时进程返回X结果或Y结果的情况下测试“doSomething”方法。有什么方法可以模拟它吗?

您可以使用
PowerMockito
mockStatic
方法进行模拟

其思想是模拟静态的
Runtime.getRuntime()
方法以返回模拟的运行时对象,并在此基础上控制
exec()的结果

一个有效的例子:

在src/main/java/sandbox/xx,xx.java中

package sandbox.xx;
导入java.io.File;
导入java.io.IOException;
XX类{
进程运行(最终字符串命令)引发IOException{
返回this.run(命令,null,null);
}
进程运行(final String命令,final String[]envp)引发IOException{
返回this.run(命令,envp,null);
}
进程运行(final String命令,final String[]envp,final File dir)引发IOException{
返回Runtime.getRuntime().exec(命令,envp,dir);
}
进程运行(最终字符串[]cmdarray)引发IOException{
返回此.run(cmdarray,null,null);
}
进程运行(最终字符串[]cmdarray,最终字符串[]envp)引发IOException{
返回此.run(cmdarray,envp,null);
}
进程运行(最终字符串[]cmdarray、最终字符串[]envp、最终文件目录)引发IOException{
返回Runtime.getRuntime().exec(cmdarray、envp、dir);
}
}
在src/test/java/sandbox/xx,XXTest.java中

package sandbox.xx;
导入java.io.IOException;
导入org.junit.Assert;
导入org.junit.Test;
导入org.junit.runner.RunWith;
导入org.mockito.ArgumentMatchers;
导入org.mockito.mockito;
导入org.powermock.api.mockito.PowerMockito;
导入org.powermock.core.classloader.annotations.PrepareForTest;
导入org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest(XX.class)//注意:不是@PrepareForTest(Runtime.class)!
公开考试{
私有静态最终字符串触发器\u ARG=“some ARG”;
应为私有静态最终字符串\u PREFIX=“gotcha!”;
私有静态最终字符串冒号=“:”;
私有静态最终字符串预期结果=预期前缀+冒号+触发器参数;
@试验
public void test()引发IOException{
最终运行时mockRuntime=PowerMockito.mock(Runtime.class);
mockStatic(Runtime.class);
Mockito.when(Runtime.getRuntime()).thenReturn(mockRuntime);
Mockito.when(mockRuntime.exec(ArgumentMatchers.eq(触发器参数)、ArgumentMatchers.any()、ArgumentMatchers.any())。然后回答(调用->{
最终流程mockProcess=PowerMockito.mock(Process.class);
Mockito.when(mockProcess.toString()).thenReturn(应为前缀+冒号+调用.getArguments()[0]);
返回过程;
});
最终XX XX=新XX();
Assert.assertEquals(预期结果,xx.run(触发器参数).toString());
Assert.assertNull(xx.run(“其他参数”);
}
}

希望这有帮助

模拟运行时总是很棘手的,特别是当它是一个复杂的项目时。我以前也这么做过,但要坚持一个模仿框架几乎是不可能的。因此,我对项目类使用Easymock,对运行时使用Powermock。但它确实很复杂,不容易为下一个开发人员阅读。 所以我的建议是在项目中保留一个类,该类只调用一个运行时方法(对于您来说,它是exec,同样,如果您想调用halt()方法,请将其保留在单独的类中)。然后使用运行时方法对该类使用Mockito,并验证相同的mock。
祝你好运

当你说我“不能重构”时,这意味着你甚至不能修改它一点?我可以修改一点,但我不能改变类来通过运行时…我想你是对的!!我忘了使用mockStatic,只使用了mock。我现在要考试了!谢谢。虽然它似乎在模仿它…但最终它似乎忽略了模仿,实际上是在寻找要执行的脚本。。。有什么想法吗?
@RunWith(PowerMockRunner.class)
@PrepareForTest(Runtime.class)
public class TestClass {

  @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
  }
}