3 回答
如果该readInput()
方法执行某些操作,例如,说:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
return in.readLine();
然后,您可能可以通过以下测试逃脱:
InputStream oldSystemIn = System.in;
InputStream mockSystemIn = context.mock(InputStream.class);
System.setIn(mockSystemIn);
context.checking(new Expectations() {{
// mock expected method calls and return values
}});
// execute
// verify
System.setIn(oldSystemIn);
您可以使用系统规则而不是模拟 System.out 和 System.in。
public void MyTest {
@Rule
public TextFromStandardInputStream systemInMock = emptyStandardInputStream();
@Test
public void readTextFromStandardInputStream() {
systemInMock.provideText("your file name");
//your code that reads "your file name" from System.in
}
}
Stefan Birkner 的回答给了我解决这个问题所需的方向。我在下面发布了用于解决此问题的代码。
为什么:发生的情况是,使用 Birkner 的库,您只能读取与最初使用规则实例化一样多的输入。如果您想迭代地写入端点,您可以使用管道破解来做到这一点,但这并没有太大的区别,您不能在函数实际运行时通过管道写入输入,所以您还不如使用Birkner的版本,他的@Rule更简洁。
解释:在管道黑客和Birkner的代码中,在被测试的客户端中,多次调用创建从 System.in 读取的任何对象将导致阻塞问题,一旦第一个对象打开与管道的连接或System.in,其他的不行。我不知道为什么这完全适用于 Birkner 的代码,但是对于 Pipe,我认为这是因为你只能打开 1 个流到对象。请注意,如果您在第一个缓冲读取器上调用 close,然后在从测试中调用它后尝试在客户端代码中重新打开 System.in,那么第二次打开尝试将失败,因为写入端的管道已关闭也是。
解决方案:解决这个问题的简单方法,可能不是最好的,因为它需要修改实际项目的源代码,但不是以可怕的方式(还)。因此,与其在实际项目的源代码中创建多个 BufferedReader,不如创建一个缓冲读取器,并传递相同的读取器引用或使其成为类的私有变量。请记住,如果您必须将其声明为静态,则不应在静态上下文中对其进行初始化,因为如果这样做,则在测试运行时, System.setIn 将在读取器在客户端中初始化之后被调用。因此它将轮询所有 readLine/whatever 调用,就像您尝试从 System.in 创建多个对象一样。请注意,要在阅读器(在本例中为 BufferedReader)的调用之间分离读取,您可以在原始设置中使用换行符来分隔它们。这样,它会在正在测试的客户端的每个调用中返回您想要的内容。