Jmock - 如何自动化&模拟出控制台用户输入?

时间:2012-04-21 04:12:31

标签: java junit jmock

我有一些功能,我想模拟从main调用(静态:我也读过这个 - jmock mocking a static method)。我最近读到JMock不支持静态函数的模拟。那么,必须从main调用相关代码(这给我一个问题),并且必须在带有main的类中...

Sample source

Test code

现在,我想确保我的主人有一个测试,以确保该文件在继续之前存在。问题是,我的程序从控制台获取用户输入,所以我不知道如何模拟出来?我是否只是降低到那个级别的粒度,指定在发生的每一个方面发生了什么,这样我只能在函数中写一个返回用户输入的操作?我知道要很好地编写测试,当测试运行时,他们不应该要求用户输入,我应该在我的测试中以某种方式指定它。

我认为它与以下内容有关: How to use JMock to test mocked methods inside a mocked method 我对JMock不太好......

3 个答案:

答案 0 :(得分:2)

如果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);

答案 1 :(得分:1)

您可以使用System Rules代替模拟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
  }
}

答案 2 :(得分:0)

Stefan Birkner的回答给了我解决这个问题所需的方向。我已经发布了以下用于解决此问题的代码。

Solved tests: Birkner's version (recommended)

Solved tests: piped version

Changed source:

为什么:发生的事情是,使用Birkner的库,您只能读取与最初使用规则实例化的输入。如果你想迭代地写入端点,你可以通过管道攻击来做到这一点,但它没有太大的区别,你不能在函数实际运行时通过管道写入输入,所以你不妨使用Birkner的版本,他的@Rule更简洁。

解释:在管道攻击和Birkner的代码中,在被测试的客户端中,多次调用创建从System.in读取的任何对象将导致阻塞问题,其中,第一次对象已经打开了与Pipe或System.in的连接,其他人则无法。我不知道为什么这对Birkner的代码来说确实如此,但是对于Pipe我认为这是因为你只能打开1个流到对象。请注意,如果您在第一个缓冲的阅读器上调用close,然后在从测试中调用它后尝试在客户端代码中重新打开System.in,则第二次尝试打开将失败,因为编写器端的管道已关闭同样。

解决方案:解决这个问题的简单方法,可能不是最好的方法,因为它需要修改实际项目的来源,但不是以可怕的方式(尚未)。因此,不要在实际项目的源代码中使用多个BufferedReader创建,创建一个缓冲读取器,并传递相同的读者引用或使其成为类的私有变量。请记住,如果必须将其声明为静态,则不应在静态上下文中初始化它,因为如果执行此操作,则在测试运行时,将在客户端初始化读取器之后调用System.setIn。因此,它将在所有readLine /任何调用上进行轮询,就像您尝试从System.in创建多个对象一样。 请注意,要在读取器的调用之间隔离读取,在本例中为BufferedReader,您可以使用换行符在原始设置中隔离它们。这样,它会在正在测试的客户端中的每个调用中返回您想要的内容。