Java 如何在编写JUnit时绕过Runtime.getRuntime()?
我有一个类,其中Runtime.getRuntime()用于从命令行执行脚本,并获得进一步处理的结果 但是当我为这个类编写JUnit时,我找不到模拟/避免这个Runtime.getRuntime().exec()的方法 我不能使用EasyMock、PowerMock或除Mockito之外的任何其他模拟apiJava 如何在编写JUnit时绕过Runtime.getRuntime()?,java,unit-testing,junit,singleton,mockito,Java,Unit Testing,Junit,Singleton,Mockito,我有一个类,其中Runtime.getRuntime()用于从命令行执行脚本,并获得进一步处理的结果 但是当我为这个类编写JUnit时,我找不到模拟/避免这个Runtime.getRuntime().exec()的方法 我不能使用EasyMock、PowerMock或除Mockito之外的任何其他模拟api 请给我一个解决这个问题的方法,因为这会影响代码覆盖率。您必须重构。将Runtime.getRuntime().exec()提取到单独的类中: public class Shell {
请给我一个解决这个问题的方法,因为这会影响代码覆盖率。您必须重构。将
Runtime.getRuntime().exec()
提取到单独的类中:
public class Shell {
public Process exec(String command) {
return Runtime.getRuntime().exec(command);
}
}
现在不再调用getRuntime()
显式地将Shell
类以某种方式注入到您的测试类中:
public class Foo {
private final Shell shell;
public Foo(Shell shell) {
this.shell = shell;
}
//...
shell.exec(...)
}
在JUnit测试中,通过将模拟的Shell
类传递给构造函数,简单地注入该类:
@Mock
private Shell shellMock;
new Foo(shellMock);
旁注:是的,我不是在用一个实现创建一个Shell
接口。你介意吗?莫基托不是。奖励:您现在可以验证是否调用了正确的流程:
verify(shellMock).exec("/usr/bin/gimp");
托马兹·努尔基维茨提供了一个极好的答案。但还有一种选择 您可以将
Runtime.getRuntime()
移动到您正在测试的类中它自己的方法中;然后用Mockito间谍测试它。在Mockito spy中,您可以使用创建mock运行时的版本覆盖此特定方法,然后对其执行任何操作
然而,Tomasz的方法更干净,我完全推荐它。我只是想说,有另一种方法可以做到这一点,而不必求助于Powermock。我使用了子分类和重写(正如Michael C.Feathers在《有效地处理遗留代码》一书中所解释的那样)
假设我们有以下代码:
public class CannotChange{
public CannotChange(){}
public void TryingToTest() throws IOException {
...
Process proc = Runtime.getRuntime().exec("command");
...
}
}
将运行时代码提取到受保护的方法中:
public void TryingToTest() throws IOException {
...
Process proc = execute("command");
...
}
protected Process execute(string command){
return Runtime.getRuntime().exec(command);
}
然后在测试类中创建一个扩展CannotChange类和重写的类
执行
嗨,谢谢你的快速回复!!但是,还有别的办法吗?在哪里我不必更改构造函数?也不要使用像“this.shell=shell;”这样的setter@user1147417:我不认为有任何可能性,至少没有PowerMock<代码>静态
s是邪恶的!well Can Can use powermock:(这是一个问题,有时感觉JUnit和Java之间需要更强大的相互关系和兼容性!!或者我遗漏了什么?哎呀,David,在再次发布相同的内容之前,我没有看到您的答案。非常感谢您提供了一个出色的解决方案。
public class CannotChangeTest{
private class CannotChangeForTesting extends CannotChange{
public CannotChangeForTesting(){ super(); }
@Override
public Process execute(String command){
return null; //or a mocked object
}
}
@Test
public void TestMethod(){
CannotChange cannotChange = new ForTestCannotChange();
cannotChange.TryingToTest();
}
}