3

我发现为这种方法编写单元测试真的很难,当用户键入退出命令时它基本上退出程序。

系统退出类:

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

4 回答 4

3

您应该将PowerMockito罐子包含到您的项目中,而不仅仅是普通的 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);
    }
}
于 2012-09-02T19:26:13.753 回答
1

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

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

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

于 2012-09-02T08:58:54.230 回答
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来创建一个对象,该对象将使用您的模拟作为其exiter. 然后,您可以运行您的测试,并verify在您的 mock 上运行SystemExit

于 2012-09-02T22:11:46.087 回答
0

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

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

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

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

于 2012-09-02T19:35:14.037 回答