Java 在测试中调用生产代码以隐藏一些不相关的细节时,您是否编写了帮助器方法?

Java 在测试中调用生产代码以隐藏一些不相关的细节时,您是否编写了帮助器方法?,java,unit-testing,kotlin,testing,Java,Unit Testing,Kotlin,Testing,假设我有一个示例测试用例(用Kotlin编写,但在这里并不重要) 正如您所看到的,我正在将一个null值作为第二个参数传递给process方法,因为它在本例中不相关,所以我可以这样做 但我担心的是,每次我阅读这个测试时,我都想知道为什么这个null值会被传递,在这个上下文中它意味着什么,所以我解决这个问题的方法是创建一些帮助器方法,为我隐藏这个null。那么我的测试结果会是这样的 @Test fun `should do something`() { // given val e

假设我有一个示例测试用例(用Kotlin编写,但在这里并不重要)

正如您所看到的,我正在将一个
null
值作为第二个参数传递给
process
方法,因为它在本例中不相关,所以我可以这样做

但我担心的是,每次我阅读这个测试时,我都想知道为什么这个
null
值会被传递,在这个上下文中它意味着什么,所以我解决这个问题的方法是创建一些帮助器方法,为我隐藏这个null。那么我的测试结果会是这样的

@Test
fun `should do something`() {
    // given
    val expected = "expected result"

    // when
    val result = process("foo")

    //then
    assertThat(result).isEqualTo(expected)
}

private fun process(foo: String): String {
    return productionClass.process(foo, null)
}
然后,当我阅读测试时,我很清楚发生了什么,但像往常一样,这种解决方案也有利弊。这些是我发现的:

专业人士

  • 提高了测试的可读性
  • 生产代码与测试的少量分离(生产API的更改只会导致此助手中断,而不会导致100个其他测试)
  • 隐藏测试中的低级细节,我只对结果感兴趣,它是如何发生的并不重要(也许…或者我在这里错了)
缺点

  • 我不确定这个测试是做什么的,因为它可以在这个助手中做很多奇怪的事情
  • 创建一个助手可能会导致创建许多其他助手,然后我将无法找到正在发生的事情

我真的很好奇你的意见。你如何处理这个问题?或者这根本不是问题?

我会给出一些反对列出的优点的论点

测试(在我看来)应该准确地显示测试的when条件(在给定的when-Then设置中)正在执行的方法。因此,就可读性而言,这意味着如果引入了另一种方法(或使用不同参数组合的多个包装器),我必须阅读更多的代码,并且对改善情况所做的很少(如果有的话),因为现在有更多的代码行,而不是更少的代码行,如果有多行代码,它将很快变得令人困惑。对我来说,可读性通常意味着更简洁的代码/更好的命名代码,而不是隐藏重要细节的额外冗余层除非参数列表特别长。此外,还有其他针对这些情况的完善的解决方案,如建筑商/工厂等

“小型解耦”-解耦是指一位代码对另一位代码的依赖性。如今,使用大多数IDE进行重构非常容易,只要掌握正确的技术。。。因此,没有必要有一种方法让生活变得更容易——生活已经相对容易了。查看“select next instance of”(选择下一个实例)功能,了解您何时突出显示了一些代码,或者“refactor method”(重构方法),它通常允许开发人员重新排序或更改方法名称/参数列表,以从方法中删除参数,并将更改级联到所有其他调用站点。有一个称为扇入/扇出的度量,它可以显示在进行或接收方法调用时一个类对另一个类的依赖程度。这可以突出显示高度耦合的代码。。。委托给另一个方法不会使代码类与类解耦


隐藏底层细节-单元测试是“白盒”测试。在您确实想知道详细信息的地方测试源代码。因为细节很重要,所以您不想在这个级别隐藏细节。间接寻址的层次越多,bug隐藏的地方就越多。如果API很难使用或令人讨厌,那么单元测试应该让这一点变得明显,如果您注意到了,您可以/应该重构,以使编写测试更清晰/更容易


也许认为需要这种方法是一个线索,你需要将这种方法分解为多个方法,这样你才能更干净地测试函数???

谢谢你的评论,基于此,我也确实认为这个API应该改进,这样这个问题就不会出现了。通过一个小的解耦,我的意思是我可以避免这种情况,当我更改API时,我需要修复许多测试,所以当它隐藏在这个助手中时,我需要在一个地方更改它,但前提是它是相对较小的重构,但是我的IDE可能可以处理这个问题,我不应该担心这种情况隐藏低层次的细节——单元测试是“白盒”测试。当我测试这个API下发生的事情时,这不是一个问题吗?然后,此API中的任何重构都会导致我的测试中断,因此我可能应该避免此类测试。但是,当我们只讨论调用的开始(执行api)时,我应该明确地说明我在做什么,以清楚地说明为什么在我的测试中会发生“这种情况”,当我们讨论集成测试时,它会改变什么吗?您使用的是什么IDE?
@Test
fun `should do something`() {
    // given
    val expected = "expected result"

    // when
    val result = process("foo")

    //then
    assertThat(result).isEqualTo(expected)
}

private fun process(foo: String): String {
    return productionClass.process(foo, null)
}