从TDD的角度来看,我已经了解到,当某些行为中断时,只有一项测试失败 - 其他失败通常会产生误导。如果这是真的,我有两个比较器,其中一个比较器使用另一个比较器,你如何测试?我正在考虑将模拟用于"子比较器,"但是,如果使用"父比较器对列表进行排序,你会怎么注入这个模拟?"
例如:
public class SomeParentComparator implements Comparator<SomeType> {
private static final SomeSubComparator subComparator1 = new SubComparator();
private static final SomeOtherSubComparator subComparator2 = new SomeOtherSubComparator();
@Override
public int compare(SomeType someType1, SomeType someType2) {
return new CompareToBuilder()
.append(someType1.foo, someType2.foo, subComparator1)
.append(someType1.bar, someType2.bar, subComparator2)
.toComparison();
}
}
在上文中,假设我已经测试过&#34;子比较器&#34; (SomeSubComparator和SomeOtherSubComparator)。在这种情况下如何在没有&#34;真依赖性的情况下测试SomeParentComparator&#34;在子比较器上(例如,模拟子比较器)?真的,这应该是一个&#34;工作流程&#34;单元测试,只需确保&#34;子比较器&#34;被叫,对吗?怎么样?
答案 0 :(得分:1)
由于您直接在类对象的实例变量中初始化SomeParentComparator
和subComparator1
,因此subComparator2
很难独立测试。
我建议为这两个字段设置setter和getter,并使用setter或constructor初始化它们。
然后,您可以使用setters
设置您的模拟subComaparators
。
您还可以创建模拟数据,其中subComparator
比较并不重要。我可以给出一些类比,比如你想要用它们的名字和姓氏对People
个对象进行排序。您的父级比较器按名字排序,子比较器按姓氏排序。然后,您的模拟数据将是People
的列表,其姓氏都相同。
答案 1 :(得分:1)
理想情况下,所有类都会注入所有依赖项而不是隐式(在您的情况下,通过私有静态字段)。但是,删除所有隐式依赖项肯定会多次使代码过于复杂。在这种情况下,您有两种单元测试选项:
构建单元测试运行器,以便只有依赖类的测试通过才能运行依赖类的测试。
使用类似Powermock的东西在单元测试期间绕过封装并注入模拟的依赖项。这将允许依赖类的测试通过,即使依赖类已被破坏。
在您给出的示例中,我无法看到您无法明确依赖关系的任何原因。这些字段不需要是静态的 - 因为这个类的所有对象都将以完全相同的方式运行。因此,最好有一个明确的“子比较器”集合。并期望调用者明确添加它们。
答案 2 :(得分:0)
我认为你误解了TDD的建议。
您实际上有两个可以独立测试的子比较器类。然后你有了#34;父母&#34;比较器,将子比较器的实例作为硬连线组件。只需单独测试它们......没有任何花哨的嘲弄。
当然,父级的正确性取决于子比较器的正确性。但由于前者和后者是不可分割的,因此将父母视为黑匣子以进行测试更容易也更正确。
想到另一种方式,@ ShanuGupta的回答表明你应该打开父比较器的抽象来允许嘲笑。据推测,您有充分的理由封装了子比较器实例。现在你可以使用DI创建父构造函数了......但是你再一次有效地打破了这个抽象。
或者另一种方式。假设你打破了封装。现在你有了一个(概念上)应该为所有可能的子比较器类工作的父类。 (因为有人可以更改代码以使用不同的比较器而不更改父本身。)但这可能意味着您有一组更复杂的行为要进行测试。
答案 3 :(得分:0)
在这种情况下,我不会为嘲笑而烦恼,我会将整个事物(所有3个比较器)作为一个单元进行测试。
我想测试看起来像下面这样:
@Test
public void parent_with_smaller_foo_and_equal_bar_is_smaller() {
var parentA = aParent().withFoo("A").withBar("C");
var parentB = aParent().withFoo("B").withBar("C");
assertThat(parentA).isLessThan(parentB);
}
@Test
public void parent_with_equal_foo_and_equal_bar_is_equal() {
var parentA = aParent().withFoo("A").withBar("C");
var parentB = aParent().withFoo("A").withBar("C");
assertThat(parentA).isEqualByComparingTo(parentB);
}
等等。如果您将上述内容写成:
(A,C)<(B,C)
(A,C)=(A,C)
然后看起来我们需要至少3个案例来测试所有三个比较器:
(B,C)>(A,C)
(A,B)<(A,C)
(A,C)>(A,B)
我会将SubComparator
和SomeOtherSubComparator
保留为包私有类,并将其视为SomeParentComparator
的实现详细信息。
只需5个测试用例,我就不会考虑找出失败原因成为真正的问题。