如何对没有参数的 void 方法进行单元测试
How to unit test a void method with no arguments
我需要测试 class 以确定在给定特定输入的情况下是否发生了相关操作。代码是这样的:
protected static void receiveInput() {
String command;
boolean b = true;
Scanner scanner = new Scanner(System.in);
while (b) {
command = scanner.next();
switch(command) {
case "first":
System.out.println("First!");
break;
case "second":
System.out.println("Second!");
break;
case "third":
System.out.println("Third!");
break;
default:
System.out.println("\n***** Invalid *****\n");
}
System.out.println("\n");
}
scanner.close();
}
如果我能以某种方式控制命令字符串并跟踪扫描仪对象,我可能可以获得非常彻底的单元测试。出于某种原因,我实际上不允许注入这两个对象作为此方法的参数。以不同的方式进行此测试有哪些选择?
这是使函数更易于测试的完美示例。此函数不接受输入也不产生输出,仅通过副作用影响世界,使其完全无法通过标准方法进行测试。
重构此函数以使其更易于测试:
- 不要求用户通过扫描器输入,将用户的输入作为输入参数。
- 不打印结果,return它。
函数的调用者然后可以决定如何提供输入以及如何处理输出。您修改后的程序可以请求用户输入,调用函数,然后打印输出。测试框架可以提供输入列表中的输入以进行测试,并根据预期值检查输出。
您可以使用 http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#setIn(java.io.InputStream) 修改 System.in 并从文件或 ByteArrayInputStream 中读取。
同理,使用http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#setOut(java.io.PrintStream)重定向输出流。
除了 MattPutnam 的出色回答之外,还有两个针对您的方法的具体提示。
1.Change 返回字符串
protected static string receiveInput(String arg) {
String result;
String command = arg;
boolean b = true;
while (b) {
switch(command) {
case "first":
result = "first";
break;
case "second":
result = "second";
break;
case "third":
result = "third";
break;
default:
result = "\n ****Invalid*** \n";
}
}
return result;
}
2.My 偏好只是为了测试 boolean b
是否正确。如果它是真的,你就知道它起作用了,如果不是,它就没有起作用。 编辑: 请注意,这可能很危险,因为您不会检查 arg
是否一定符合字符串标准,而是检查它是否具有可接受的答案。
关于您要测试此当前方法的唯一方法是以某种方式捕获流,正如 MattPutnam 在评论中回答的那样。
您可以使用 System Rules 库测试输出。
public class YourTest {
@Rule
public SystemOutRule log = new SystemOutRule().enableLog();
@Rule
public TextFromStandardInputStream systemInMock = emptyStandardInputStream();
@Test
public void test() {
systemInMock.provideLines("first", "second");
... //execute your code
assertEquals("First!\nSecond!\n", log.getLogWithNormalizedLineSeparator());
}
}
完全披露:我是系统规则的作者。
我需要测试 class 以确定在给定特定输入的情况下是否发生了相关操作。代码是这样的:
protected static void receiveInput() {
String command;
boolean b = true;
Scanner scanner = new Scanner(System.in);
while (b) {
command = scanner.next();
switch(command) {
case "first":
System.out.println("First!");
break;
case "second":
System.out.println("Second!");
break;
case "third":
System.out.println("Third!");
break;
default:
System.out.println("\n***** Invalid *****\n");
}
System.out.println("\n");
}
scanner.close();
}
如果我能以某种方式控制命令字符串并跟踪扫描仪对象,我可能可以获得非常彻底的单元测试。出于某种原因,我实际上不允许注入这两个对象作为此方法的参数。以不同的方式进行此测试有哪些选择?
这是使函数更易于测试的完美示例。此函数不接受输入也不产生输出,仅通过副作用影响世界,使其完全无法通过标准方法进行测试。
重构此函数以使其更易于测试:
- 不要求用户通过扫描器输入,将用户的输入作为输入参数。
- 不打印结果,return它。
函数的调用者然后可以决定如何提供输入以及如何处理输出。您修改后的程序可以请求用户输入,调用函数,然后打印输出。测试框架可以提供输入列表中的输入以进行测试,并根据预期值检查输出。
您可以使用 http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#setIn(java.io.InputStream) 修改 System.in 并从文件或 ByteArrayInputStream 中读取。
同理,使用http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#setOut(java.io.PrintStream)重定向输出流。
除了 MattPutnam 的出色回答之外,还有两个针对您的方法的具体提示。
1.Change 返回字符串
protected static string receiveInput(String arg) {
String result;
String command = arg;
boolean b = true;
while (b) {
switch(command) {
case "first":
result = "first";
break;
case "second":
result = "second";
break;
case "third":
result = "third";
break;
default:
result = "\n ****Invalid*** \n";
}
}
return result;
}
2.My 偏好只是为了测试 boolean b
是否正确。如果它是真的,你就知道它起作用了,如果不是,它就没有起作用。 编辑: 请注意,这可能很危险,因为您不会检查 arg
是否一定符合字符串标准,而是检查它是否具有可接受的答案。
关于您要测试此当前方法的唯一方法是以某种方式捕获流,正如 MattPutnam 在评论中回答的那样。
您可以使用 System Rules 库测试输出。
public class YourTest {
@Rule
public SystemOutRule log = new SystemOutRule().enableLog();
@Rule
public TextFromStandardInputStream systemInMock = emptyStandardInputStream();
@Test
public void test() {
systemInMock.provideLines("first", "second");
... //execute your code
assertEquals("First!\nSecond!\n", log.getLogWithNormalizedLineSeparator());
}
}
完全披露:我是系统规则的作者。