Java编写unittest用于在用户键入控制台时退出程序

时间:2012-09-02 08:39:03

标签: java mocking mockito

我发现很难为这个方法编写单元测试,当用户输入一个quit命令时,它基本上会退出程序。

SytemExit类:

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();
    }       
}

4 个答案:

答案 0 :(得分:3)

您应该将PowerMockito Jars包含在您的项目中,而不仅仅是香草Mockito。 Powermock库设计用于模拟静态和/或最终类和方法。

以下this blog post包含描述与您类似的方案的示例代码。

基本上你需要一个与此类似的测试类...

@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);
    }
}

答案 1 :(得分:1)

没有真正的方法来测试你SystemExit类,因为执行它会导致JVM退出。您可以使用SecurityManager执行某些检测并拒绝System.exit()的操作,但测试单行代码将会带来很多工作。

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

SystemExit类中的代码很小且自足,无需测试即可查看和推理,恕我直言。

答案 2 :(得分:1)

你已经完成了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,并使用SomeClass的package-private构造函数创建一个对象,该对象将使用您的模拟作为其exiter 。然后,您可以在模拟verify上运行测试和SystemExit

答案 3 :(得分:0)

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

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

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

如果代码是微不足道的,我建议不要围绕它编写单元测试,因为它只是没有足够高的投资回报。你的情况实际上加剧了我的主张,想一想你需要多少努力来测试这样的简单代码并将其与增益进行比较......这真的值得付出努力。这真的让你更信任自己的代码吗?

相关问题