Java编写unittest,用于在控制台中用户类型退出时退出程序
我发现为这种方法编写单元测试非常困难,当用户键入quit命令时,它基本上会退出程序 系统出口等级:Java编写unittest,用于在控制台中用户类型退出时退出程序,java,mocking,mockito,Java,Mocking,Mockito,我发现为这种方法编写单元测试非常困难,当用户键入quit命令时,它基本上会退出程序 系统出口等级: public class SystemExit { public void exit(int status) { System.exit(status); } } 我的静态方法: public static void exitWhenQuitDetected() { final SystemExit systemExit = new SystemExit(); f
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());
}
}
这里有些不太对劲,因为我正在努力对检测到的方法exitWhenQuitDetected进行单元测试(我使用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();
}
}
没有真正的方法来测试您的
SystemExit
类,因为执行它会导致JVM退出。您可能可以使用SecurityManager
来检测并拒绝System.exit()
,但是测试一行代码需要大量的工作
您做了正确的事情-您将功能拉入了一个小类中。如果我是你,我会在上面放一个接口,然后通过接口将它注入解析代码。然后在测试中,您可以插入一个mock,并测试您的解析代码是否使用正确的退出代码调用mock上的exit()
方法
SystemExit
类中的代码很小,足够独立,可以在不进行测试的情况下查看和推理。您应该将JAR包含到项目中,而不仅仅是普通的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%的工作,将实际存在的代码放在一个单独的类中,没有自己的逻辑。您的困难是由于使用静态方法造成的 我建议将检测到的
退出
设置为非静态。将它放在一个类中,您可以在需要时实例化它,并且可以使用模拟的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
,并使用SomeClass
的包私有构造函数创建一个对象,该对象将使用您的模拟作为其出口。然后,您可以运行测试,并在您的模拟系统出口上验证
请添加您的模拟代码。这正是我所要求的,我正在努力为此进行测试。欢迎使用堆栈溢出!我们鼓励你这样做。如果你有,请将其添加到问题中-如果没有,请先研究并尝试你的问题,然后再回来。我没有发现任何奇怪的地方,但我建议你做两件事。1:trim
要与之比较的行(字符串行
)退出
。2:不要使用equals(…)
而是使用eqalsIgnoreCase(…)
。谢谢,我觉得很奇怪,因为我无法为此编写测试。谢谢dty,同意你的说法,我也不想测试SystemExit,我想在检测到时退出单元测试方法,基本上模拟SysytemExit,BufferedReader等类,并验证SystemExit.exit(0)方法在看到“退出”输入时确实被调用。嗯,我之所以这样做是因为我认为问题是关于SystemExit
类的,正如您所说,不应该测试它。但是exitWhenQuitDetected
方法有一个while
和一个if
-因此它肯定应该被测试。问题是该方法是静态的。我将很快发布一个答案,解释如何最好地测试这一点。+1是一个务实的答案,要求最小的变化。我仍然喜欢我的答案(没有代码更改),但我有偏见:)它可以工作,但唯一的问题是它模仿了系统类的所有方法。是否仍然只模拟退出方法?是的,您可以使用createPartialMock()
。。。