更改System.in并使扫描仪使用一个ByteArrayInputStream?

时间:2013-02-17 05:49:48

标签: java testing junit user-input

我的任务是编写测试程序来评估学生的家庭作业是否有效。 这些学生正在用Java编写一个Rock,Paper,Scissors游戏并通过要求用户在命令行中输入来进行单轮课程,该游戏通过n轮游戏进行。 所有这些学生都将使用一个或多个Scanner对象来读取控制台的输入,因此我需要让我的测试程序模拟一些预定的输入并检查预期的输出。 我重写System.in,所以当学生调用Scanner myReader = new Scanner(System.in);时,我会指示输入是什么(使用ByteArrayInputStream)。 想知道我是如何开始的:

public class TestRockPaperScissors extends RockPaperScissors{
public static void main(String[] args){
    InputStream stdin = System.in;
    try {
    System.setIn(new ByteArrayInputStream("<test inputs here>".getBytes()));
    RockPaperScissors.main(null); // This will be student code in another file.
    } finally {
        System.setIn(stdin);
    }

}

问题是,这仅在学生仅使用System.in创建单个扫描仪时才有效。否则,我会收到错误,因为第二个扫描程序没有输入使用.next()。

TL; DR ...我如何为任意数量的扫描仪模拟控制台输入,因为我看不到RockPaperScissors.main(null)调用的来源?

2 个答案:

答案 0 :(得分:1)

要求学生通过从InputStream获取值并将结果写入PrintStream来编写运行RockPaperScissors的对象,即编写以下接口的实现

public interface RockPaperScissors {
    void runGame(InputStream in, PrintStream out) throws IOException;
}

这将允许他们使用以类System.in和System.out作为参数的类实例来测试自己的程序。

这将允许您通过传递包含输入序列的自己的ByteArrayInputStream以及包含程序生成的输出的您自己的ByteArrayOutputStream来对其程序进行单元测试,您也可以验证它。

顺便说一下,学生不应该学会单独测试自己的代码吗?

答案 1 :(得分:1)

您可以使用System Rules库的StandardOutputStreamLogTextFromStandardInputStream规则为命令行界面编写更清晰的测试。

public class RockPaperScissorsTest() {
  @Rule
  public StandardOutputStreamLog log = new StandardOutputStreamLog();

  @Rule
  public TextFromStandardInputStream systemInMock = emptyStandardInputStream();

  @Test
  public void test1() {
    systemInMock.provideText("<test input>");
    RockPaperScissors.main(null);
    assertTrue(log.getLog().contains("<expected output>"));
  }

  @Test
  public void test2() {
    systemInMock.provideText("<another test input>");
    RockPaperScissors.main(null);
    assertTrue(log.getLog().contains("<expected output>"));
  }
}