How to test a Command Line Interface (CLI)?
我的Java应用程序由两部分组成:
对于1.我使用JUnit进行单元测试,但是你会为2做什么?
如何为命令行界面创建自动化测试?
我有完全相同的问题,落在这里并没有找到一个好的答案,所以我想我会发布解决方案,我最终将作为未来降落在这里的任何人的起点。
我在CLI之后写了我的测试(对我来说很遗憾,我知道),所以首先我确保CLI是以可测试的方式编写的。它看起来像这样(我省略了异常处理并简化了许多以使其更具可读性):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 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接受的每个命令编写方法允许JUnit测试几乎完美地模拟用户输入。由于在调用
首先,测试原始输入是否正确清理是很好的,您可以通过编写
1 2 3 4 5 6 7 8 9 | @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]); } |
它也很容易覆盖一些边缘情况:
1 2 3 4 5 6 7 8 9 10 | @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]); } |
接下来,我们可以通过监视stdout来测试invididual命令方法。我这样做了(我在这里找到):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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的
当然,CLI应用程序通常不仅仅是打印到控制台。假设您的程序将信息保存到文件中,您可以像这样测试它(从JUnit 4.7开始):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | @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方法是否正确处理它。
对于CLI,请尝试BATS(Bash自动测试系统):https://github.com/bats-core/bats-core
来自文档:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | example.bats contains #!/usr/bin/env bats @test"addition using bc" { result="$(echo 2+2 | bc)" ["$result" -eq 4 ] } @test"addition using dc" { result="$(echo 2 2+p | dc)" ["$result" -eq 4 ] } $ bats example.bats ? addition using bc ? addition using dc 2 tests, 0 failures |
蝙蝠核
使用Apache commons exec从Java程序执行命令。
Apache Commons exec