Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/369.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在编写JUnit时绕过Runtime.getRuntime()?_Java_Unit Testing_Junit_Singleton_Mockito - Fatal编程技术网

Java 如何在编写JUnit时绕过Runtime.getRuntime()?

Java 如何在编写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()用于从命令行执行脚本,并获得进一步处理的结果

但是当我为这个类编写JUnit时,我找不到模拟/避免这个Runtime.getRuntime().exec()的方法

我不能使用EasyMock、PowerMock或除Mockito之外的任何其他模拟api


请给我一个解决这个问题的方法,因为这会影响代码覆盖率。

您必须重构。将
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();
   }
}