关于Sytem.in和System.out的JUnit测试 [英] JUnit Testing around Sytem.in and System.out
问题描述
我被要求在从命令行运行和运行的旧版Java应用程序中引入单元测试.基本上,主循环会打印出一个菜单,用户会输入一些内容并显示更多数据.
I have been asked to introduce unit test in a legacy Java Application that runs and operates from Command Line. Basically the main loop prints out a Menu, the user inputs something and it shows more data.
这个Main类说明了应用程序的工作方式.
This Main class illustrate how the application works.
public class Main{
static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
public static void main(String argv[]) throws IOException{
while (true) {
char input = (char) reader.read();
if(input == 'x'){
return;
}
System.out.println(input);
}
}
}
我希望我的测试方法看起来像这样
I'd like my test methods to look something like this
public void testCaseOne(){
Main.main();
String result = "";
result = sendInput("1");
assertEqual(result, "1");
result = sendInput("x");
assertEqual(result,"");
}
我知道System.setOut()
和System.setIn()
方法,但是由于reader.read()
方法阻塞了我的线程,因此我无法找出一种使System.setIn()
方法在这种情况下工作的方法.
I am aware of the System.setOut()
and System.setIn()
methods, but I cannot figure out a way to make the System.setIn()
method work in this context, since the reader.read()
method is blocking my thread.
我的测试设计是否错误?
有没有一种方法可以设计sendInput()
方法来处理阻塞的reader.read()调用?
Is my test design wrong?
Is there a way to design the sendInput()
method to work through the blocking reader.read() call?
推荐答案
我建议重构代码以允许输入/输出流被注入,然后可以对其进行模拟.如果您可以将其更改为类似
I would suggest refactoring the code to allow the input/output streams to be injected, and then you can mock them. If you couuld change it to something like
public class Main{
static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
public static void main(String argv[]) throws IOException{
new YourClass(reader,System.out).run();
}
}
public class YourClass { // I don't know what your class is actually doing, but name it something appropriate
private final InputReader reader;
private final PrintStream output;
public YourClass(InputReader reader, PrintStream output) {
this.reader = reader;
this.output = ouptut;
}
public void run() {
while (true) {
char input = (char) reader.read();
if(input == 'x')
return;
output.println(input);
}
}
此设计可完成以下几项工作:
This design does a couple of things:
-
它将逻辑带出您的主类.通常,主要方法实际上只是用于启动应用程序.
It takes the logic out of your main class. Typically a main method is really just used for launching an application.
它使YourClass
更容易进行单元测试.在测试中,您可以简单地模拟输入/输出.
It makes YourClass
more easily unit testable. In your tests, you can simply mock out the input/output.
更新此重构如何帮助解决IO阻塞问题
Update to how this refactoring helps with the blocking IO problem
通过使读取器/输出如上所示可注入,您实际上不需要使用实际的System.in和System.out-可以使用模拟代替.这样就不需要实际进行阻塞读取了.
By making the reader/output injectable as shows above, you don't actually need to use the real System.in and System.out - you can use a mock instead. This eliminates the need to actually have blocking reads.
public void testCaseOne(){
// pseudocode for the mock - this will vary depending on your mock framework
InputReader reader = createMock(InputReader);
// the first time you read it will be a "1", the next time it will be an "x"
expect(reader.read()).andReturn("1");
expect(reader.read()).andReturn("x");
PrintStream stream = createMock(PrintStream);
// only expect the "1" to get written. the "x" is the exit signal
expect(stream.println("1"));
new YourClass(reader,stream).run();
verifyMocks();
}
这篇关于关于Sytem.in和System.out的JUnit测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!