嗨,这是我第一次尝试使用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;
}
答案 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方法。
答案 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; }
}
}