JUnit 测试布局

JUnit testing layout

我有一个特定的字典项目,它接受用户输入并将它们写入数据库。输入(目前)是通过扫描仪(System.in)接收的,我有多个案例,例如:

  1. 输入单词和定义
  2. 输入同义词
  3. 打印字典

像这样的事情。如何使用 JUnit 复制用户输入?

这个问题很宽泛;但要获得的基本部分是:要充分利用 JUnit,您应该将其视为 automation 的一部分。因此,您必须专注于删除 任何阻止这种情况的东西

换句话说:您的应用程序需要一个可用于 "feed" 输入的界面。意思是:你的应用程序应该 而不是 包含任何从 System.in 读取的代码。相反,您的应用程序应该有一个简单的界面,例如 addWordWithDefinition(String word, String definition)。并且它应该有稍后查询此类信息的方法。

现在编写测试用例非常简单:

@Test
public void testAddAndGet() {
   String someWord = "whatever";
   String definition = "who cares";
   YourApplication underTest = new YourApplication(...
   underTest.addWordWithDefinition(someWord, definition);
   assertThat(underTest.getDefinitionFor(someWord), is(definition));

你从那里开始;您考虑极端情况(例如一个或两个参数都为空),等等。您尝试绝对 而不是 测试您的实现的内部结构。因此,理想情况下,当您更改 "persistence" 机制时;你的测试仍然有效。

鬼猫说得对。 我想完成它的回答。

在您的应用程序中,有 2 个不同的职责:

  • 为您的每个业务案例捕获用户请求(输入单词和定义、输入同义词、打印字典):用户界面职责。
  • 处理逻辑:逻辑责任。

好的设计会尽量避免混合职责。 所以,你应该为 :

创建一个 class
  • 正在捕获用户请求。它从 System.in 捕获用户输入,并将数据分派给适当的处理方法 class.
  • 处理逻辑。这是逻辑class。

它有什么优势?
您的应用程序的逻辑现在在 class 处理逻辑中。
通过这种方式,您可以将单元测试集中在这个 class 上,以检查您的应用程序是否按预期处理逻辑。

有了这样的设计,您无需担心扫描器,因为它是一个成熟的组件,可以正常工作:您不需要对其进行单元测试。

-- 编辑:回答您关于如何使用 System.in

实现集成测试的评论

我看了代码。
首先,对于您的实际代码,您无法使用依赖于捕获的多个输入的扫描仪进行集成测试,因为 classic 模拟工具,因为 Mockito 不允许这样做(class 是最终的)。
您可以对输入流进行存根,但与在相同方法中一样,您采用多个输入(选项选择 + 值),您不能对两个输入进行存根。
所以,我们必须找到绕过它的技巧。 解决该问题的一种方法是创建两种使用应用程序的方法:一种是用户逐个输入输入,另一种是一次性输入所有输入,并使用分隔符进行单元测试。

一切都不是可操作的,但你可以遵循原则。

单元测试将是这样的:

@Test
public void printOptionWithAddedWordInDictionary() throws Exception {
  final ByteArrayInputStream inputStreamStubbed = new   ByteArrayInputStream("a|dog|super animal!".getBytes());
  InputReceiver inputReceiver = new InputReceiver(inputStreamStubbed, "\|");
  inputReceiver.printOptions();
}

如您所见,您现在有两个构造函数和两个新的私有字段:

private InputStream inputStream;
private Scanner input;

public InputReceiver() {
  inputStream = System.in;
  scanner = new Scanner(inputStream);
}

  // for unit testing
 InputReceiver(InputStream inputStream, String delimiter) {
  this.inputStream = inputStream;
  scanner = new Scanner(inputStream);
  scanner.useDelimiter(delimiter);
}

第二个是用于测试的私有包。