我发现很难为这个方法编写单元测试,它基本上是在用户键入退出命令时退出程序的。
系统出口类别:
public class SystemExit {
public void exit(int status) {
System.exit(status);
}
}
我的静态方法:
public static void exitWhenQuitDetected() {
final SystemExit systemExit = new SystemExit();
final String QUIT = "quit";
String line = "";
try {
final InputStreamReader input = new InputStreamReader(System.in);
final BufferedReader in = new BufferedReader(input);
while (!(line.equals(QUIT))) {
line = in.readLine();
if (line.equals(QUIT)) {
System.out.println("You are now quiting the program");
systemExit.exit(1);
}
}
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
}
这里有些地方不太对劲,因为我正在努力对exitWhenQuitTDetected方法进行单元测试(我使用Mockito进行嘲讽)。我该如何模拟InputStreamReader并验证SystemExit.exit方法在看到退出时被调用?你能帮我解释一下吗?谢谢
添加了我目前正在进行的测试,它不起作用。
@Test
@Ignore
public void shouldExitProgramWhenTypeQuit() {
String quit = "quit";
SystemExit systemExit = mock(SystemExit.class);
try {
BufferedReader bufferedReader = mock(BufferedReader.class);
when(bufferedReader.readLine()).thenReturn(quit + "n");
SomeClass.exitWhenQuitDetected();
verify(systemExit, times(1)).exit(1);
} catch (IOException e) {
e.printStackTrace();
}
}
您应该在项目中包含PowerMockito Jars,而不仅仅是香草Mockito。Powermock库是为模拟静态和/或最终类和方法而设计的。
下面的这篇博客文章包含了描述与您类似场景的示例代码。
本质上,你需要一个类似的测试类。。。
@RunWith(PowerMockRunner.class)
@PrepareForTest({System.class, ClassToTest.class})
public class SystemExitTest {
@Test
public void shouldCallSystemExit() {
PowerMockito.mockStatic(System.class);
ClassToTest.methodToTest();
PowerMockito.verifyStatic();
System.exit(0);
System.out.println("If this message displays them System.exit() was mocked successfully");
}
}
给定这个简单的实现类。。。
public class ClassToTest {
public static void methodToTest() {
// do some stuff
System.exit(0);
}
}
您已经完成了90%的工作,将实际退出的代码放在一个没有自己逻辑的单独类中。你的困难是由你使用静态方法造成的。
我建议使exitWhenQuitDetected
不是静态的。把它放在一个类中,您可以在需要时实例化它,并且可以用模拟的SystemExit
创建它。像这样的东西。
public class SomeClass{
private final SystemExit exiter;
private final static String QUIT = "quit";
public SomeClass(){
this(new SystemExit());
}
SomeClass(SystemExit exiter){
this.exiter = exiter;
}
public static void exitWhenQuitDetected() {
String line = "";
try {
final InputStreamReader input = new InputStreamReader(System.in);
final BufferedReader in = new BufferedReader(input);
while (!(line.equals(QUIT))) {
line = in.readLine();
if (line.equals(QUIT)) {
System.out.println("You are now quiting the program");
exiter.exit(1);
}
}
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
}
// ...
}
然后,在测试中,您可以制作SystemExit
的mock,并使用SomeClass
的包私有构造函数来创建一个将使用mock作为其exiter
的对象。然后,您可以运行测试,并在模拟SystemExit
上运行verify
。
没有真正的方法来测试SystemExit
类,因为使用它会导致JVM退出。您可能可以使用检测并拒绝System.exit()
的SecurityManager
做一些事情,但要测试一行代码需要做大量工作。
你做了正确的事情——你把功能拉到了一个小类中。如果我是你,我会在上面放一个接口,并通过接口将其注入解析代码中。然后在测试中,您可以注入一个mock,并测试您的解析代码是否使用正确的退出代码在mock上调用exit()
方法。
SystemExit
类中的代码很小,而且是自包含的,可以在不进行测试的情况下查看和推理,IMHO。
提供了大量的技术解决方案。我想指出另一个观点:
这段代码不应该真正进行单元测试。
从单元测试中获得的最佳收益是将它们应用于复杂的业务代码,尤其是在有大量分支的情况下。
在代码琐碎的情况下,我建议不要围绕它编写单元测试,因为它根本没有足够高的投资回报。你的情况实际上加剧了我的说法,想想你测试这样的简单代码所花费的精力,并将其与增益进行比较。。这真的值得付出努力吗。这真的会让你更加信任自己的代码吗?