简体   繁体   English

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

[英]Java Writing unittest for exiting a program when user type quit in the console

I found really hard to write unit test for this method, it basically exits the program when user types a quit command. 我发现很难为这个方法编写单元测试,它基本上在用户键入quit命令时退出程序。

SytemExit class: SytemExit类:

public class SystemExit {
    public void exit(int status) {
        System.exit(status);
    }
}

My static method: 我的静态方法:

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

Something is not quite right here as I am struggling to unit test the method exitWhenQuitDetected (I am using Mockito for mocking). 因为我正在努力对方法exitWhenQuitDetected进行单元测试(我正在使用Mockito进行模拟),所以这里的东西并不完全正确。 How would I mock the InputStreamReader and verify the SystemExit.exit method gets called when it sees a quit? 我如何模拟InputStreamReader并验证SystemExit.exit方法在看到退出时被调用? Can you shed some lights on this please? 请问你能解决这个问题吗? Thanks. 谢谢。

Added the test I am working on at the moment, it's not working. 添加了我正在进行的测试,它不起作用。

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

You should include the PowerMockito Jars into your project rather than just vanilla Mockito. 您应该将PowerMockito Jars包含在您的项目中,而不仅仅是vanilla Mockito。 The Powermock library is designed for mocking Static and/or Final classes and methods. Powermock库专为模拟静态和/或最终类和方法而设计。

The following this blog post contains example code describing a similar scenario to yours. 以下此博客文章包含描述与您类似的方案的示例代码。

Essentially you require a test class similar to this... 基本上你需要一个类似于这个的测试类......

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

Given this simple implementation class... 鉴于这个简单的实现类......

public class ClassToTest {

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

There is no real way to test you SystemExit class since exercising it will cause the JVM to exit. 没有真正的方法来测试SystemExit类,因为执行它会导致JVM退出。 You might be able to do something with a SecurityManager which detects and rejects the System.exit() , but that's going to be a whole lot of work to test a single line of code. 您可以使用SecurityManager来检测和拒绝System.exit() ,但是测试单行代码需要做大量的工作。

You've done the right thing - you've pulled the functionality into a small class. 你已经做了正确的事 - 你已经把功能拉到了一个小班级。 If I were you, I would put an interface on it and inject it via the interface into the parsing code. 如果我是你,我会在其上放一个接口,并通过接口将其注入解析代码。 Then in your test you can inject a mock and test that your parsing code calls the exit() method on the mock with the right exit code. 然后在测试中,您可以注入一个模拟并测试您的解析代码使用正确的退出代码调用模拟上的exit()方法。

The code in the SystemExit class is small and self-contained enough to look at and reason about without testing, IMHO. SystemExit类中的代码很小且自足,无需测试即可查看和推理,恕我直言。

You've done 90% of the work already, by placing the actual exiting code off in a separate class with no logic of its own. 您已经完成了90%的工作,将实际的退出代码放在一个没有自己逻辑的单独类中。 Your difficulty is caused by your use of a static method. 您的困难是由您使用静态方法引起的。

I would advise making the exitWhenQuitDetected not static. 我建议让exitWhenQuitDetected不是静态的。 Put it in a class that you can instantiate when you need it, and that you can create with a mocked SystemExit . 将它放在一个可以在需要时实例化的类中,并且可以使用SystemExit创建。 Something like this. 像这样的东西。

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

  // ...
}

Then, in your test, you can make a mock of SystemExit , and use the package-private constructor of SomeClass to create an object that will use your mock as its exiter . 然后,在测试中,您可以模拟SystemExit ,并使用SomeClass的package-private构造函数创建一个将使用mock作为其exiter You can then run your test, and verify on your mock SystemExit . 然后,您可以运行测试,并在模拟SystemExit上进行verify

Plenty of technical solutions were offered. 提供了大量技术解决方案。 I would like to point out another perspective: 我想指出另一个观点:

This code should not really be unit tested. 此代码不应该真正进行单元测试。

The best gain you get out of unit tests is when applying them to complex business code, especially with a lot of branching. 从单元测试中获得的最大收益是将它们应用于复杂的业务代码,特别是在大量分支的情况下。

In cases where the code is trivial, I would advise against writing unit tests around it since it simply just does not have a high enough return of investment. 如果代码是微不足道的,我建议不要围绕它编写单元测试,因为它只是没有足够高的投资回报。 your case actually exacerbates my claim, think of the amount of effort it takes you to test simple code such as this and compare it with the gain.. does this really worth the effort. 你的情况实际上加剧了我的主张,想一想你需要多少努力来测试这样的简单代码并将其与增益进行比较......这真的值得付出努力。 Does this really make you trust your own code more? 这真的让你更信任自己的代码吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM