Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/379.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编写unittest,用于在控制台中用户类型退出时退出程序_Java_Mocking_Mockito - Fatal编程技术网

Java编写unittest,用于在控制台中用户类型退出时退出程序

Java编写unittest,用于在控制台中用户类型退出时退出程序,java,mocking,mockito,Java,Mocking,Mockito,我发现为这种方法编写单元测试非常困难,当用户键入quit命令时,它基本上会退出程序 系统出口等级: public class SystemExit { public void exit(int status) { System.exit(status); } } 我的静态方法: public static void exitWhenQuitDetected() { final SystemExit systemExit = new SystemExit(); f

我发现为这种方法编写单元测试非常困难,当用户键入quit命令时,它基本上会退出程序

系统出口等级:

public class SystemExit {
    public void exit(int status) {
        System.exit(status);
    }
}
我的静态方法:

public static void exitWhenQuitDetected() {
final SystemExit systemExit = new SystemExit();
final String QUIT = "quit";
String line = "";
try {
    final InputStreamReader input = new InputStreamReader(System.in);
    final BufferedReader in = new BufferedReader(input);
    while (!(line.equals(QUIT))) {
        line = in.readLine();
        if (line.equals(QUIT)) {
            System.out.println("You are now quiting the program");                  
            systemExit.exit(1);
        }
    }
} catch (Exception e) {
    System.err.println("Error: " + e.getMessage());
}
}   
这里有些不太对劲,因为我正在努力对检测到的方法exitWhenQuitDetected进行单元测试(我使用Mockito进行模拟)。我如何模拟InputStreamReader,并在看到退出时验证SystemExit.exit方法是否被调用?你能帮我解释一下吗?谢谢

添加了我目前正在进行的测试,它不起作用

    @Test
@Ignore
public void shouldExitProgramWhenTypeQuit() {
    String quit = "quit";           
    SystemExit systemExit = mock(SystemExit.class);
    try {
        BufferedReader bufferedReader = mock(BufferedReader.class);
        when(bufferedReader.readLine()).thenReturn(quit + "\n");
        SomeClass.exitWhenQuitDetected();
        verify(systemExit, times(1)).exit(1);
    } catch (IOException e) {           
        e.printStackTrace();
    }       
}

没有真正的方法来测试您的
SystemExit
类,因为执行它会导致JVM退出。您可能可以使用
SecurityManager
来检测并拒绝
System.exit()
,但是测试一行代码需要大量的工作

您做了正确的事情-您将功能拉入了一个小类中。如果我是你,我会在上面放一个接口,然后通过接口将它注入解析代码。然后在测试中,您可以插入一个mock,并测试您的解析代码是否使用正确的退出代码调用mock上的
exit()
方法

SystemExit
类中的代码很小,足够独立,可以在不进行测试的情况下查看和推理。

您应该将JAR包含到项目中,而不仅仅是普通的Mockito。Powermock库是为模拟静态和/或最终类和方法而设计的

下面包含描述与您类似场景的示例代码

本质上,您需要一个与此类似的测试类

@RunWith(PowerMockRunner.class)
@PrepareForTest({System.class, ClassToTest.class})
public class SystemExitTest {

    @Test
    public void shouldCallSystemExit() {

        PowerMockito.mockStatic(System.class);

        ClassToTest.methodToTest();

        PowerMockito.verifyStatic();

        System.exit(0);

        System.out.println("If this message displays them System.exit() was mocked successfully");
    }    
}
给定这个简单的实现类

public class ClassToTest {

    public static void methodToTest() {
        // do some stuff
        System.exit(0);
    }
}

提供了大量的技术解决方案。我想指出另一个观点:

这段代码实际上不应该进行单元测试

您从单元测试中获得的最佳收益是将它们应用于复杂的业务代码,特别是有大量分支的代码


在代码微不足道的情况下,我建议不要围绕它编写单元测试,因为它没有足够高的投资回报。您的案例实际上加剧了我的说法,请考虑一下您测试此类简单代码所需的工作量,并将其与收益进行比较。。这真的值得努力吗。这是否真的让您更加信任自己的代码?

您已经完成了90%的工作,将实际存在的代码放在一个单独的类中,没有自己的逻辑。您的困难是由于使用静态方法造成的

我建议将检测到的
退出
设置为非静态。将它放在一个类中,您可以在需要时实例化它,并且可以使用模拟的
SystemExit
创建该类。像这样的

public class SomeClass{
  private final SystemExit exiter;
  private final static String QUIT = "quit";
  public SomeClass(){
    this(new SystemExit());
  }

  SomeClass(SystemExit exiter){
    this.exiter = exiter;
  }

  public static void exitWhenQuitDetected() {    
    String line = "";    
    try {    
      final InputStreamReader input = new InputStreamReader(System.in);    
      final BufferedReader in = new BufferedReader(input);    
      while (!(line.equals(QUIT))) {    
        line = in.readLine();    
        if (line.equals(QUIT)) {    
          System.out.println("You are now quiting the program");                      
          exiter.exit(1);    
        }    
      }    
    } catch (Exception e) {    
      System.err.println("Error: " + e.getMessage());    
    }    
  }       

  // ...
}

然后,在测试中,您可以模拟
SystemExit
,并使用
SomeClass
的包私有构造函数创建一个对象,该对象将使用您的模拟作为其
出口。然后,您可以运行测试,并在您的模拟
系统出口上验证

请添加您的模拟代码。这正是我所要求的,我正在努力为此进行测试。欢迎使用堆栈溢出!我们鼓励你这样做。如果你有,请将其添加到问题中-如果没有,请先研究并尝试你的问题,然后再回来。我没有发现任何奇怪的地方,但我建议你做两件事。1:
trim
要与之比较的行(
字符串行
退出
。2:不要使用
equals(…)
而是使用
eqalsIgnoreCase(…)
。谢谢,我觉得很奇怪,因为我无法为此编写测试。谢谢dty,同意你的说法,我也不想测试SystemExit,我想在检测到时退出单元测试方法,基本上模拟SysytemExit,BufferedReader等类,并验证SystemExit.exit(0)方法在看到“退出”输入时确实被调用。嗯,我之所以这样做是因为我认为问题是关于
SystemExit
类的,正如您所说,不应该测试它。但是
exitWhenQuitDetected
方法有一个
while
和一个
if
-因此它肯定应该被测试。问题是该方法是静态的。我将很快发布一个答案,解释如何最好地测试这一点。+1是一个务实的答案,要求最小的变化。我仍然喜欢我的答案(没有代码更改),但我有偏见:)它可以工作,但唯一的问题是它模仿了系统类的所有方法。是否仍然只模拟退出方法?是的,您可以使用
createPartialMock()
。。。