我的任务是编写测试程序来评估学生的家庭作业是否有效。
这些学生正在用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)调用的来源?
答案 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库的StandardOutputStreamLog
和TextFromStandardInputStream
规则为命令行界面编写更清晰的测试。
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>"));
}
}