为JUnit测试提供输入

时间:2015-09-14 14:34:24

标签: java eclipse testing

嗨,这是我第一次尝试使用eclipse在java中进行单元测试。

因此,当我测试我的课程时,它需要用户输入。让我们说一个名为“add hello”的命令,这样它就会创建一个新的文本文件并为其添加单词“hello”。然后我想测试一个名为getAllLines的函数,它返回“hello”并将其与assert进行比较。

我的主要问题是如何通过junit测试模拟用户对控制台的输入。这是我尝试但它无法正常工作..

private void performUserInput(String strInput){
    ByteArrayInputStream in = new ByteArrayInputStream(strInput.getBytes());
    System.setIn(in);
}

private void releaseUserInputToSystem(){
    System.setIn(System.in);;
}

@Test
public void testSearchingInEmptyFile() {

    TextBuddy textBuddy = new TextBuddy("file.txt");

    textBuddy.run();
    performUserInput("add little brown fox");
    releaseUserInputToSystem();

    assertEquals("little brown foxx", "asd");
}

在我看来,代码永远不会达到断言。

编辑---------------------------------------------- 调试后,它被困在这里

private String[] getCommandAndArgs(){
    String[] splitCommand = scanner.nextLine().split(" "); //<<STUCK HERE
    printNewLine();
    return splitCommand;
}

4 个答案:

答案 0 :(得分:1)

使用单元测试,您应该测试TextBuddy类的单个方法(单位)。你可能有一个检查命令的方法(添加,删除,你拥有的任何东西)。写单元测试例如:

@Test
public void testCommandAdd() {
    TextBuddy  tb = new TextBuddy ();
    int command tb.parseCommand("add hello");
    assertThat(command,is(TextBuddy.ADD));
}
@Test
public void testCommandRemove() {
    TextBuddy  tb = new TextBuddy ();
    int command tb.parseCommand("remove hello");
    assertThat(command,is(TextBuddy.REMOVE));
}

然后为每个命令编写测试,例如无论如何编写/删除文件:

@Test
public void testWriteFile() throws SQLException {
    TextBuddy  tb = new TextBuddy ();
    tb.writeFile("file.txt", "hello");
    File f = new File("file.txt");
    String content = readFile(f);
    assertThat(content,is("hello"));
}

始终使用小型单元测试来测试程序的单个单元。之后你可以编写更大的测试来检查你的洞计划是否有效。

如果您不想使用public修饰符公开您的方法,您仍然可以测试它们 - 最简单的方法是将它们打包为私有并使您的测试具有相同的包(它们可以并且应该位于不同的src中-夹) 例如对于包含com.yourpackage这样的包

的类
src/com/yourpackage/YourClass.java

您可以将测试存储在

test/com/yourpackage/YourClassTest.java

然后您可以访问package-private方法。

或者您使用Reflection来访问和测试私有方法,请参阅herehere

答案 1 :(得分:0)

单元测试完全是关于自动化的,不应该依赖于用户输入。如果要测试用户输入机制,则应编写一个测试模拟用户输入要测试的输入(例如,使用Selenium进行前端测试Web应用程序)。如果要根据输入测试行为,则应构建测试,输入所有可能自动测试的可能性,并验证应用程序/程序/功能的相应正确行为。

如果指定TextBuddy.run()System.in读取内容,则在调用System.in之前重定向run()似乎是个好主意:

performUserInput("add little brown fox");
textBuddy.run();
releaseUserInputToSystem();

但是也许你可以通过添加输入流来作为run方法的参数读取来提高你的TextBuddy的可测试性:

public void run(InputStream in) {
    // use parameter in instead of System in...
}

/**
 * Convenience method to run with System.in
 */ 
public void run() {
    run(System.in);
}

在测试中,请致电run(InputStream)

ByteArrayInputStream in = new ByteArrayInputStream(strInput.getBytes());
textBuddy.run(in);

您还可以添加out参数,以便能够重定向测试方法的输出。

答案 2 :(得分:0)

我同意@LarsGendner你应该为输入任务进行模拟(做一些模拟或虚假的事情)。您可以使用一些技术,至少为此代码的某些部分提供覆盖输入(例如TextBddy)。在这种情况下,我可以提出三种方法。

  • static inputs如果您需要从经验测试中获得一些文本样本,请使用此方法。您可以使用此表单模型从现有用户那里获得一些典型行为;
  • random string generator使用此方法从头开始进行字符串生成(您可以将此方法与静态输入结合使用)
  • framework (or library)将jUnit功能扩展到数据挖掘或人工智能,如遗传算法,神经网络等。

在我的洋葱中,最后一种技术更加复杂。因此,您应该评估并执行thread-off来确定应该测试哪些部分以及哪些部分应该是您需要的代码覆盖率。请注意,根据人类行为模拟一些输入任务并不是一项微不足道的任务。

答案 3 :(得分:0)

关于原始代码,当您执行textBuddy.run();时,它会锁定期望用户输入,因此下一行(performUserInput("add little brown fox");确实提供了它正在等待的输入)永远不会被执行。

因此,为了使代码有效,您应该在调用performUserInput("add little brown fox");之前致电textBuddy.run()

@Test
public void testSearchingInEmptyFile() {
    TextBuddy textBuddy = new TextBuddy("file.txt");

    performUserInput("add little brown fox"); // changed these two lines
    textBuddy.run();                          // switched their order
    releaseUserInputToSystem();

    assertEquals("little brown foxx", "asd");
}

另一种方法是使用线程:在一个线程中执行textBuddy.run(),在另一个线程中执行performUserInput("add little brown fox")。但是,最好避免这种情况,因为线程可能会使您的测试更难以维护。

完整的演示代码:

public class TextBuddyTest {

    private InputStream performUserInput(String strInput) {
        InputStream originalSystemIn = System.in;
        ByteArrayInputStream in = new ByteArrayInputStream(strInput.getBytes());
        System.setIn(in);
        return originalSystemIn;
    }

    private void restoreSystemInputStream(InputStream originalSystemIn) {
        System.setIn(originalSystemIn);
    }

    @Test
    public void testSearchingInEmptyFile() {
        // setup
        InputStream defaultSystemIn = performUserInput("add little brown fox");

        TextBuddy textBuddy = new TextBuddy("file.txt");
        // execute
        textBuddy.run();
        // verify
        assertEquals("[add, little, brown, fox]", textBuddy.getWhatWasInput());
        // teardown
        restoreSystemInputStream(defaultSystemIn);
    }

    static class TextBuddy { // created for this demo
        Scanner scanner = new Scanner(System.in);
        String whatWasInput;
        public TextBuddy(String s) { }
        public void run() { this.whatWasInput = Arrays.toString(getCommandAndArgs()); }
        private String[] getCommandAndArgs() { return scanner.nextLine().split(" "); }
        public String getWhatWasInput() { return whatWasInput; }
    }

}