关于Sytem.in和System.out的JUnit测试 [英] JUnit Testing around Sytem.in and System.out

查看:102
本文介绍了关于Sytem.in和System.out的JUnit测试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我被要求在从命令行运行和运行的旧版Java应用程序中引入单元测试.基本上,主循环会打印出一个菜单,用户会输入一些内容并显示更多数据.

I have been asked to introduce unit test in a legacy Java Application that runs and operates from Command Line. Basically the main loop prints out a Menu, the user inputs something and it shows more data.

这个Main类说明了应用程序的工作方式.

This Main class illustrate how the application works.

public class Main{

    static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

    public static void main(String argv[]) throws IOException{
        while (true) {
            char input = (char) reader.read();

            if(input == 'x'){
                return;
            }

            System.out.println(input);
        }
    }
}

我希望我的测试方法看起来像这样

I'd like my test methods to look something like this

public void testCaseOne(){
    Main.main();
    String result = "";

    result = sendInput("1");
    assertEqual(result, "1");

    result = sendInput("x");
    assertEqual(result,"");
}

我知道System.setOut()System.setIn()方法,但是由于reader.read()方法阻塞了我的线程,因此我无法找出一种使System.setIn()方法在这种情况下工作的方法.

I am aware of the System.setOut() and System.setIn() methods, but I cannot figure out a way to make the System.setIn() method work in this context, since the reader.read() method is blocking my thread.

我的测试设计是否错误? 有没有一种方法可以设计sendInput()方法来处理阻塞的reader.read()调用?

Is my test design wrong? Is there a way to design the sendInput() method to work through the blocking reader.read() call?

推荐答案

我建议重构代码以允许输入/输出流被注入,然后可以对其进行模拟.如果您可以将其更改为类似

I would suggest refactoring the code to allow the input/output streams to be injected, and then you can mock them. If you couuld change it to something like

public class Main{

    static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

    public static void main(String argv[]) throws IOException{
        new YourClass(reader,System.out).run();
    }
}

public class YourClass { // I don't know what your class is actually doing, but name it something appropriate
  private final InputReader reader;
  private final PrintStream output;

  public YourClass(InputReader reader, PrintStream output) {
       this.reader = reader;
       this.output = ouptut;
  }

  public void run() {

        while (true) {
        char input = (char) reader.read();

        if(input == 'x')
            return;

        output.println(input);
  }
}

此设计可完成以下几项工作:

This design does a couple of things:

  1. 它将逻辑带出您的主类.通常,主要方法实际上只是用于启动应用程序.

  1. It takes the logic out of your main class. Typically a main method is really just used for launching an application.

它使YourClass更容易进行单元测试.在测试中,您可以简单地模拟输入/输出.

It makes YourClass more easily unit testable. In your tests, you can simply mock out the input/output.

更新此重构如何帮助解决IO阻塞问题

Update to how this refactoring helps with the blocking IO problem

通过使读取器/输出如上所示可注入,您实际上不需要使用实际的System.in和System.out-可以使用模拟代替.这样就不需要实际进行阻塞读取了.

By making the reader/output injectable as shows above, you don't actually need to use the real System.in and System.out - you can use a mock instead. This eliminates the need to actually have blocking reads.

public void testCaseOne(){
    // pseudocode for the mock - this will vary depending on your mock framework
    InputReader reader = createMock(InputReader);
    // the first time you read it will be a "1", the next time it will be an "x"
    expect(reader.read()).andReturn("1");
    expect(reader.read()).andReturn("x");

    PrintStream stream = createMock(PrintStream);
    // only expect the "1" to get written. the "x" is the exit signal
    expect(stream.println("1"));

    new YourClass(reader,stream).run();
    verifyMocks();
}

这篇关于关于Sytem.in和System.out的JUnit测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆