基于测试控制台的应用程序/程序 – Java

所有,

我用Java编写了一个基于命令行的PhoneBook应用程序。 该应用程序基本上要求用户的一些细节,如姓名,年龄,地址和电话号码,并将它们存储在一个文件中。 其他操作包括按名称,电话号码等查找电话簿。所有细节都通过控制台输入。

我正在尝试为我已经实现的每个function编写JUnit测试用例,但是无法弄清楚如何将实现代码中的System.in重定向到我的JUnit测试方法中的某些内容,这些方法将在我的实际代码停止时提供这些值用户输入?

例:

我的实现代码有:

 BufferedReader is = new BufferedReader (new InputStreamReader(System.in)); System.out.println("Please enter your name:"); String name = is.readLine(); // My test cases stop at this line. How can I pass command line values ie redirect System.in to my test based values? 

希望它有意义

为什么不编写应用程序以将Reader作为输入? 这样,您可以使用FileReader(testFile)轻松替换InputStreamReader(System.in) FileReader(testFile)

 public class Processor { void processInput(Reader r){ ... } } 

然后是两个实例:

 Processor live = new Processor(new InputStreamReader(System.in)); Processor test = new Processor(new FileReader("C:/tmp/tests.txt"); 

习惯于对界面进行编码将为您的程序的几乎每个方面带来巨大的好处!

另请注意, Reader是在Java程序中处理基于字符的输入惯用方法。 应保留InputStream s用于原始字节级处理。

系统 。 setIn (new BufferedInputStream( new FileInputStream(“input.txt”) ));

我建议你把代码分成三个部分:

  • 读取输入(如示例中的name
  • 做你需要做的输入
  • 打印结果

您不需要测试读取输入和打印结果,因为Java代码已经由编写Java的人员测试过。

您需要测试的唯一事情就是正在做的事情,无论是什么。 unit testing的命名就是这样,因为它们单独测试代码单元。 您不测试整个程序,您测试自包含且具有明确定义的function的小块。

在unit testing中,您不应该依赖输入/输出操作。 您应该在unit testing中直接提供输入和预期输出。 有时使用文件读取操作来提供输入或输出是很方便的(例如,如果数据量很大),但作为一般规则,您在unit testing中进入输入/输出的次数越多,它们变得越复杂,您更有可能不做单位,而是集成测试。

在你的情况下,你name某种方式使用name 。 如果这是唯一的参数,那么创建一个方法 – 让我们称之为nameConsumer – 取名字,做某事并返回其结果。 在您的unit testing中,执行以下操作:

 @Test public void testNameConsumer() { // Prepare inputs String name = "Jon"; String result = nameConsumer(name); assertEquals("Doe", result); } 

printlnreadLine调用移动到其他方法并使用nameConsumer ,但不在unit testing中。

在这里阅读更多相关信息:

保持简单,它是值得的。

库系统规则提供了规则TextFromStandardInputStream,用于在JUnit测试中模拟输入。

 public class YourAppTest { @Rule public TextFromStandardInputStream systemInMock = emptyStandardInputStream(); @Test public void test() { systemInMock.provideText("name\nsomething else\n"); YourApp.main(); //assertSomething } } 

有关详细信息,请查看“ 系统规则”文档 。

这需要一个基本的循环控制台应用程序,并使用oxbow_lakes的答案中的想法使其可测试。

适合阶级:

 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; public class TestableLoopingConsoleExample { public static final String INPUT_LINE_PREFIX = "> "; public static final String EXIT_COMMAND = "exit"; public static final String RESPONSE_PLACEHOLDER = "...response goes here..."; public static final String EXIT_RESPONSE = "Exiting."; public static void main(String[] cmdLineParams_ignored) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); PrintStream out = new PrintStream(System.out); PrintStream err = new PrintStream(System.err); try { new TestableLoopingConsoleExample().main(cmdLineParams_ignored, in, out); } catch (Exception e) { //For real use, catch only the exactly expected types err.println(e.toString()); } } 

…继续…

  public void main(String[] cmdLineParams_ignored, BufferedReader in, PrintStream out) throws IOException { System.out.println("Enter some text, or '" + EXIT_COMMAND + "' to quit"); while (true) { out.print(INPUT_LINE_PREFIX); String input = in.readLine(); out.println(input); if (input.length() == EXIT_COMMAND.length() && input.toLowerCase().equals(EXIT_COMMAND)) { out.println(EXIT_RESPONSE); return; } out.println(RESPONSE_PLACEHOLDER); } } } 

测试(JUnit4):

 import static org.junit.Assert.assertEquals; import static testableloopingconsoleapp.TestableLoopingConsoleExample.EXIT_COMMAND; import static testableloopingconsoleapp.TestableLoopingConsoleExample.EXIT_RESPONSE; import static testableloopingconsoleapp.TestableLoopingConsoleExample.INPUT_LINE_PREFIX; import static testableloopingconsoleapp.TestableLoopingConsoleExample.RESPONSE_PLACEHOLDER; import org.junit.Before; import org.junit.Test; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.io.StringReader; public class TestableLoopingConsoleExampleTest { private final ByteArrayOutputStream out = new ByteArrayOutputStream(); private final ByteArrayOutputStream err = new ByteArrayOutputStream(); @Before public final void resetOutputStreams() { out.reset(); err.reset(); } 

…继续…

  @Test public void testableMain_validInputFromString_outputAsExpected() throws Exception { String line1 = "input line 1\n"; String line2 = "input line 2\n"; String line3 = "input line 3\n"; String exitLine = EXIT_COMMAND + "\n"; BufferedReader in = new BufferedReader(new StringReader( line1 + line2 + line3 + exitLine )); String expectedOutput = INPUT_LINE_PREFIX + line1 + RESPONSE_PLACEHOLDER + "\n" + INPUT_LINE_PREFIX + line2 + RESPONSE_PLACEHOLDER + "\n" + INPUT_LINE_PREFIX + line3 + RESPONSE_PLACEHOLDER + "\n" + INPUT_LINE_PREFIX + exitLine + EXIT_RESPONSE + "\n"; String[] ignoredCommandLineParams = null; new TestableLoopingConsoleExample().main(ignoredCommandLineParams, in, new PrintStream(out)); assertEquals(expectedOutput, out.toString()); } }