2010-11-19 141 views
9

全部,基于测试控制台的应用程序/程序 - Java

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

我想为我已经实现的每个功能编写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 i.e. redirect System.in to my test based values? 

希望这是有道理的

+0

你可以找到一些示例代码来做你在这里描述的内容:http://illegalargumentexception.blogspot.com/2010/09/java-systemconsole-ides-and-testing.html但它主要是一种实现oxbow_lakes在他的回答中描述。 – McDowell 2010-11-20 10:42:27

回答

11

为什么不写你的应用程序采取Reader作为输入?这样一来,你可以很容易地用FileReader(testFile)

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

然后两个实例替换InputStreamReader(System.in)

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

习惯编码到一个接口会在你的程序的几乎所有方面带来极大的好处!

还请注意,Reader处理Java程序中基于字符的输入的惯用方式。应该为原始字节级处理保留InputStream

+0

我不理解你。上面的代码如何在我的示例中工作?所以如果我必须在我的测试方法中传递命令行值,我必须使用文件'tests.txt'?如果是这样的话,我希望通过我的测试方法传递值,而不是通过创建文件来传递值。 – 2010-11-20 00:06:52

+0

这两个'Reader'具有相同的接口。你为单元测试使用'FileReader',因为它不需要用户输入(为了测试不同的输入而准备文本文件)。您在执行程序时使用'InputStreamReader(System.in)',因此它仍然会直接要求用户输入。 – Santa 2010-11-20 00:11:11

3
+0

你能否详细说明你的答案?为什么我会使用文件“input.txt”? – 2010-11-20 00:09:01

+1

@ darkie15:这只是一个例子。 – thejh 2010-11-20 11:31:10

+0

@ darkie15:你也可以使用'PipedInputStream'和'PipedOutputStream'。 – thejh 2010-11-20 12:10:03

3

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

  • 读取输入(如在你的例子name
  • 你需要做的是输入
  • 打印的结果是什么

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

你需要测试的唯一东西是在做什么,不管是什么。单元测试就是这样命名的,因为它们单独测试代码单元。你不测试整个程序,你测试的小块是独立的,并有一个明确的功能。

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

在你的情况下,你以某种方式使用name。如果这是唯一的参数,那么创建一个方法 - 我们称之为nameConsumer - 接受该名称,执行某些操作并返回结果。在单元测试中,做这样的事情:

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

移动你的printlnreadLine调用其他方法和在单元测试中使用周围nameConsumer,但不是。

了解更多关于此这里:

保持简单,付出总有回报。

2

System Rules提供了用于在JUnit测试中模拟输入的规则TextFromStandardInputStream

public class YourAppTest { 
    @Rule 
    public TextFromStandardInputStream systemInMock = emptyStandardInputStream(); 

    @Test 
    public void test() { 
    systemInMock.provideText("name\nsomething else\n"); 
    YourApp.main(); 
    //assertSomething 
    } 
} 

详情看看System Rules documentation

+0

非常非常有用的图书馆!在这里使用它:https://github.com/binwiederhier/syncany/blob/7ee6174877a646c78e2f5faa36115d01bf6cc9ec/syncany-cli/src/test/java/org/syncany/tests/cli/InitCommandTest.java#L137 – binwiederhier 2014-03-15 19:43:54

1

这需要basic looping console application并使其可测试,使用oxbow_lakes' answer的想法。

类-正确:

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()); 
    } 

} 
+0

Phwoaaa .... that不如一些测试可以。 Upvoted tho,thx! – Crowie 2017-03-28 01:52:55

相关问题