【问题标题】:Unit testing a console input method Java单元测试控制台输入法Java
【发布时间】:2024-05-03 10:30:02
【问题描述】:

如何对以下方法进行单元测试?

public static String grabString() {
BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
do {
  try {
    // call the readline method of the buffered reader object.
    return r.readLine();
  } catch (Exception e) {
  }
} while (true);}

如果我像这样从测试类调用这个方法

String getInput = grabString();

并用它测试它

assertEquals(getInput, "hello");

是否可以使用代码在控制台中输入“hello”而无需键入,以便单元测试立即运行?

【问题讨论】:

  • 您可以测试 JDK 中内置的代码,但您可能会认为它已经可以工作。目前尚不清楚您的循环试图实现什么,也不清楚您如何触发诸如异常。我不希望在无限循环中解决问题,而是用AssetionError 包装它,因为它不应该发生而且你不知道如何处理它。

标签: java unit-testing input console


【解决方案1】:

我建议您不要使用静态方法,而是使用带有 InputStream 作为字段的对象(最终是单例)。 然后你可以在你的生产代码中使用真正的 System.in,在测试中使用假的 InputStream。

类似这样的:

public class MyStreamReader {

    private InputStream in;

    public MyStreamReader(InputStream in) {
        this.in = in;
    }

    public String grabString() {
        BufferedReader r = new BufferedReader(new InputStreamReader(in));
        do {
            try {
                // call the readline method of the buffered reader object.
                return r.readLine();
            } catch (Exception e) {
            }
        } while (true);
    }

}

在生产代码中,您将使用 System.in 流构建实例(例如 new MyStreamReader(System.in))。

在测试中,您将使用假 InputStream 进行测试:

@Test
public void testGrabString() throws Exception {
    String expected = "test input from console";
    ByteArrayInputStream fakeIS = new ByteArrayInputStream(expected.getBytes());
    MyStreamReader myStreamReader = new MyStreamReader(fakeIS);

    String actual = myStreamReader.grabString();
    assertEquals(expected, actual);
}

【讨论】:

  • 似乎是我想要的。谢谢。
  • 不客气。您能否将其标记为答案?
【解决方案2】:

您可以通过以下方式使用Robot 类:

 Robot r = new Robot();
 r.keyPress(/*Keycode for your input*/);
 r.keyRelease(/*Keycode for your input*/);

对于应该在键盘上按下的每个键。

但我怀疑这是否有意义,因为您将测试 Java API 代码,并且您应该假设这些方法有效!

无论你想要实现什么,像你这样的无限循环都不是一个好方法!

【讨论】:

  • 一般情况下,需要注意的是,在keyPress()keyRelease()之间通常需要一个延迟,以便应用程序注册按键。见here