我的 Java 应用程序由两部分组成:
- 核心库(类、接口(interface)等)
- 使用核心库的命令行界面 (CLI)
对于 1. 我使用 JUnit 进行单元测试,但是对于 2. 你会怎么做?
如何为命令行界面创建自动化测试?
最佳答案
我遇到了完全相同的问题,登陆这里但没有找到好的答案,所以我想我会发布我最终得出的解决方案,作为 future 登陆这里的任何人的起点。
我在 CLI 之后编写测试(我知道我很丢脸),所以首先我确保 CLI 是以可测试的方式编写的。它看起来像这样(我省略了异常处理并做了很多简化以使其更具可读性):
public class CLI {
public static void main(String... args) {
new CLI(args).startInterface();
}
CLI(String... args) {
System.out.println("Welcome to the CLI!");
// parse args, load resources, etc
}
void startInterface() {
BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));
while (true) {
String[] input = sanitiseInput(consoleReader.readLine());
if (input[0].equalsIgnoreCase("help") {
help();
} else if (input[0].equalsIgnoreCase("exit") {
break;
} else if (input[0].equalsIgnoreCase("save") {
save(input);
} else {
System.out.println("Unkown command.");
}
}
}
String[] sanitiseInput(String rawInput) {
// process the input and return each part of it in order in an array, something like:
return rawInput.trim().split("[ \t]+");
}
void help() {
// print help information
System.out.println("Helpful help.");
}
void save(String[] args) {
// save something based on the argument(s)
}
}
开始测试。 CLI
不是公共(public)图书馆的一部分,因此它应该受到图书馆用户的保护。如前所述here ,您可以使用默认访问修饰符使其包私有(private)。这使您的测试可以完全访问该类(只要它们在同一个包中),同时仍然保护它,所以这就是照顾。
为 CLI 接受的每个命令编写一个方法允许 JUnit 测试几乎完美地模拟用户输入。由于在您调用 startInterface()
之前对象不会从标准输入中读取,因此您可以简单地实例化它并测试各个方法。
首先,最好测试原始输入是否已正确清理,您可以通过为 sanitiseInput()
编写 JUnit 测试来轻松完成。我写了这样的测试:
@Test
public void commandAndArgumentsSeparatedBySpaces() throws Exception {
String[] processedInput = uut.sanitiseInput("command argument1 argument2");
assertEquals("Wrong array length.", 3, processedInput.length);
assertEquals("command", processedInput[0]);
assertEquals("argument1", processedInput[1]);
assertEquals("argument2", processedInput[2]);
}
覆盖一些边缘情况也很容易:
@Test
public void leadingTrailingAndIntermediaryWhiteSpace() throws Exception {
String[] processedInput = uut.sanitiseInput(" \t this \twas \t \t a triumph \t\t ");
assertEquals("Wrong array length.", 4, processedInput.length);
assertEquals("this", processedInput[0]);
assertEquals("was", processedInput[1]);
assertEquals("a", processedInput[2]);
assertEquals("triumph", processedInput[3]);
}
接下来我们可以通过监控标准输出来测试各个命令方法。我这样做了(我发现了 here ):
private CLI uut;
private ByteArrayOutputStream testOutput;
private PrintStream console = System.out;
private static final String EOL = System.getProperty("line.separator");
@Before
public void setUp() throws Exception {
uut = new CLI();
testOutput = new ByteArrayOutputStream();
}
@Test
public void helpIsPrintedToStdout() throws Exception {
try {
System.setOut(new PrintStream(testOutput));
uut.help();
} finally {
System.setOut(console);
}
assertEquals("Helpful help." + EOL, testOutput.toString());
}
换句话说,将 JVM 的 out
替换为您可以在练习前查询的内容,然后将旧控制台设置回测试的拆卸中。
当然,CLI 应用程序通常不仅仅是打印到控制台。假设您的程序将信息保存到一个文件中,您可以这样测试它(从 JUnit 4.7 开始):
@Rule
public TemporaryFolder tempFolder = new TemporaryFolder();
@Test
public void informationIsSavedToFile() throws Exception {
File testFile = tempFolder.newFile();
String expectedContent = "This should be written to the file.";
uut.save(testFile.getAbsolutePath(), expectedContent);
try (Scanner scanner = new Scanner(testFile)) {
String actualContent = scanner.useDelimiter("\\Z").next();
assertEquals(actualContent, expectedContent);
}
}
JUnit 将负责创建一个有效文件并在测试运行结束时将其删除,让您可以自由地测试 CLI 方法是否正确处理了它。
关于java - 如何测试命令行界面 (CLI)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27472270/