2

我最近一直在写很多单元测试。有一种情况我找不到干净的解决方案......

假设您有一种方法:

public void bigMethod() {
    // a lot of code goes in here
}

为了让你的生活更轻松和代码更简洁,你通常会将这样的野兽分解为更小的内部方法:

public void bigMethod() {
    a();
    b();
    c();
    // etc.
}

您可以独立测试所有内部方法(a()、b()、c() 等)。问题是 bigMethod() 也应该进行测试,但它唯一要做的就是链接其他一些方法的调用,并且这些方法已经过彻底测试!

您如何处理这种情况?你不能不测试 bigMethod(),因为你需要确保 a()、b() 和 c() 是按正确的顺序调用的。但是为 bigMethod() 编写测试会导致大量重复测试。每次都减少这种重复会很麻烦,因为你会经常这样做。

我想到的一个想法是:

public void bigMethod() {
    helperA.a();
    helperB.b();
    helperC.c();
    // etc.
}

在这种情况下,您测试每个帮助程序类,然后确保 bigMethod() 按顺序调用它们。很好很干净,但是在项目中引入了很多非常小的类。

帮助测试忍者!

4

4 回答 4

2

通常,最佳实践是让您的单元测试测试bigMethod(),因为它是公开的方法,并且测试不知道内部的私有辅助方法。

bigMethod()正如您所指出的,如果您重构.

所以我的建议是重写你的测试以专注于bigMethod()然后不必担心代码重复。

于 2012-10-15T17:20:41.977 回答
1

您找不到好的解决方案的原因是将方法拆分为连续的部分并没有真正改善事情。事实上,它可能使调试变得更加困难,因为您必须跨方法边界共享状态,可能使用实例变量。

我知道这不是您想听到的答案,但是如果您真的想改进代码,您将退后一步,重新分析所做的事情bigMethod并重写它,将其各种功能分成具有适当接口的类。理想情况下,您还会重构bigMethod被调用的位置,但我意识到这可能超出了您分配的任务的范围。

于 2012-10-15T17:26:22.427 回答
1

首先,如果和是公共方法a(),则以下所有文本都是有意义的。b()c()

bigMethod()测试关注内部调用的后果,意思是调用a()后面跟着b()和后面跟着c()

这完全是另一种情况,而不是独立测试这些方法中的每一个。

所以根据我的说法,添加一个特定的测试bigMethod()并没有揭示一些重复,而是一个新的有趣的案例来检查:内部调用的协作

我会保留您的第一个代码版本并对其进行测试:)

实际上,这似乎是项目交付中类似的常见问题:

假设三个项目分别开发并最终收集起来。

三种可能的做法:

  • 仅独立测试三个项目
  • 等待单独测试三个项目的混合
  • 测试这两种方式!

从逻辑上讲,希望有第三种可能性;单元测试也是如此。

a()b()c()可能有意外的行为,但不会阻止bigMethod()获得预期的结果,相反,bigMethod()尽管独立方法的测试成功,但可能会产生意外的结果。

于 2012-10-15T17:29:01.643 回答
0

我认为解决方案对您来说不清楚的原因是因为您没有真正考虑并定义a(),b()和的性质c()。您肯定需要弄清楚以下哪一项a()b()并且c()是:

  1. 内部的,不可分割的子部分bigMethod()在它之外没有任何意义。

  2. 作为类公共契约一部分的方法,有助于其凝聚力,并且可以独立于外部调用。

  3. 毕竟不属于该类的方法。将它们取出将有利于班级的凝聚力,并使它们更容易重复使用。

一旦你弄清楚了,如何测试它们的答案就很容易了。

  1. 只需bigMethod()像原子块一样进行测试,不要试图摆弄其内部子部分的可见性范围以使其可测试。

  2. 测试a()b()并且c()独立。然后进行测试bigMethod(),使用部分模拟并验证子方法是否以正确的顺序调用。您还可以 testbigMethod()的结果,使其更像是集成测试而不是单元测试,但您提到了重复问题。

  3. 测试a()b()并且c()独立。然后进行测试bigMethod(),对其对象使用模拟并验证bigMethod()与这些对象的对话是否正确。

于 2012-10-16T09:04:18.983 回答