我有一个类在其某些方法中使用
Runtime.getRuntime().exec ...
例如:
public class MyClass {
public void doSomething() {
...do something...
Runtime.getRuntime().exec ...
...do something else
}
}
不幸的是我"无法重构"该课程由于一些要求。我想在这个类上创建jUnit测试,我发现很难模拟Runtime类。
让我们说我想测试" doSomething"运行时进程返回X结果或Y结果的情况下的方法。有没有办法嘲笑它?
答案 0 :(得分:3)
您可以使用PowerMockito
和mockStatic
方法执行此操作。
我们的想法是模拟静态Runtime.getRuntime()
方法以返回模拟的运行时对象,并且可以控制exec()
的结果
@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
}
}
答案 1 :(得分:0)
一个工作示例:
在 src / main / java / sandbox / xx 中,XX.java
package sandbox.xx;
import java.io.File;
import java.io.IOException;
class XX {
Process run(final String command) throws IOException {
return this.run(command, null, null);
}
Process run(final String command, final String[] envp) throws IOException {
return this.run(command, envp, null);
}
Process run(final String command, final String[] envp, final File dir) throws IOException {
return Runtime.getRuntime().exec(command, envp, dir);
}
Process run(final String[] cmdarray) throws IOException {
return this.run(cmdarray, null, null);
}
Process run(final String[] cmdarray, final String[] envp) throws IOException {
return this.run(cmdarray, envp, null);
}
Process run(final String[] cmdarray, final String[] envp, final File dir) throws IOException {
return Runtime.getRuntime().exec(cmdarray, envp, dir);
}
}
在 src / test / java / sandbox / xx 中,XXTest.java
package sandbox.xx;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest(XX.class) // watch it: not @PrepareForTest(Runtime.class)!
public class XXTest {
private static final String TRIGGER_ARG = "some arg";
private static final String EXPECTED_PREFIX = "gotcha!";
private static final String COLON = ": ";
private static final String EXPECTED_RESULT = EXPECTED_PREFIX + COLON + TRIGGER_ARG;
@Test
public void test() throws IOException {
final Runtime mockRuntime = PowerMockito.mock(Runtime.class);
PowerMockito.mockStatic(Runtime.class);
Mockito.when(Runtime.getRuntime()).thenReturn(mockRuntime);
Mockito.when(mockRuntime.exec(ArgumentMatchers.eq(TRIGGER_ARG), ArgumentMatchers.any(), ArgumentMatchers.any())).thenAnswer(invocation -> {
final Process mockProcess = PowerMockito.mock(Process.class);
Mockito.when(mockProcess.toString()).thenReturn(EXPECTED_PREFIX + COLON + invocation.getArguments()[0]);
return mockProcess;
});
final XX xx = new XX();
Assert.assertEquals(EXPECTED_RESULT, xx.run(TRIGGER_ARG).toString());
Assert.assertNull(xx.run("some other arg"));
}
}
希望这会有所帮助
答案 2 :(得分:0)
模拟运行时总是很棘手,特别是如果它是一个复杂的项目。我之前做过,但是要坚持一个模拟框架几乎是不可能的。因此,我将Easymock用于项目类,将Powermock用于运行时。但这确实很复杂,而且对于下一个开发人员来说不容易理解。 因此,我的建议是在您的项目中保留一个类,该类恰好调用一个Runtime方法(对您来说它是exec,同样,如果您要调用halt()方法,请将其保留在单独的类中)。然后使用运行时方法对该类使用Mockito并验证相同的模拟。 祝你好运!