Java编写单元测试,用于在用户在控制台中键入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());
}
}   

这里有些地方不太对劲,因为我正在努力对exitWhenQuitTDetected方法进行单元测试(我使用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();
    }       
}

您应该在项目中包含PowerMockito Jars,而不仅仅是香草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%的工作,将实际退出的代码放在一个没有自己逻辑的单独类中。你的困难是由你使用静态方法造成的。

我建议使exitWhenQuitDetected不是静态的。把它放在一个类中,您可以在需要时实例化它,并且可以用模拟的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的mock,并使用SomeClass的包私有构造函数来创建一个将使用mock作为其exiter的对象。然后,您可以运行测试,并在模拟SystemExit上运行verify

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

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

SystemExit类中的代码很小,而且是自包含的,可以在不进行测试的情况下查看和推理,IMHO。

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

这段代码不应该真正进行单元测试。

从单元测试中获得的最佳收益是将它们应用于复杂的业务代码,尤其是在有大量分支的情况下。

在代码琐碎的情况下,我建议不要围绕它编写单元测试,因为它根本没有足够高的投资回报。你的情况实际上加剧了我的说法,想想你测试这样的简单代码所花费的精力,并将其与增益进行比较。。这真的值得付出努力吗。这真的会让你更加信任自己的代码吗?

最新更新