什么';测试使用Java中另一个比较器的比较器的最佳方法是什么?
从TDD的角度来看,我已经了解到,当某个行为中断时,只有一个测试应该失败——其他的失败通常是误导性的。如果这是真的,我有两个比较器,其中一个比较器使用另一个比较器,你如何测试它?我曾考虑过使用mock作为“sub comparator”,但在使用“parent comparator”对列表进行排序时,如何注入这个mock呢 例如:什么';测试使用Java中另一个比较器的比较器的最佳方法是什么?,java,unit-testing,tdd,comparator,Java,Unit Testing,Tdd,Comparator,从TDD的角度来看,我已经了解到,当某个行为中断时,只有一个测试应该失败——其他的失败通常是误导性的。如果这是真的,我有两个比较器,其中一个比较器使用另一个比较器,你如何测试它?我曾考虑过使用mock作为“sub comparator”,但在使用“parent comparator”对列表进行排序时,如何注入这个mock呢 例如: public class SomeParentComparator implements Comparator<SomeType> { priv
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();
}
}
公共类SomeParentComparator实现Comparator{
private static final SomeSubComparator subComparator1=新的SubComparator();
私有静态最终SomeOtherSubComparator subComparator2=新建SomeOtherSubComparator();
@凌驾
公共int比较(SomeType someType1,SomeType someType2){
返回新的CompareToBuilder()
.append(someType1.foo、someType2.foo、子比较1)
.append(someType1.bar、someType2.bar、子比较2)
.toComparison();
}
}
在上面,假设我已经测试了“子比较器”(SomeSubComparator和SomeOtherSubComparator)。在这种情况下,如何在不对子比较程序(例如,模拟子比较程序)具有“真正依赖性”的情况下测试SomeParentComparator?实际上,这应该是一个“工作流”单元测试,只需确保调用“子比较器”,对吗?如何测试?您的
SomeParentComparator
很难独立测试,因为您直接在类对象的实例变量中初始化子comparator1
和子comparator2
我建议为这两个字段使用setter和getter,并使用setter或构造函数初始化它们
然后,您可以使用设置器
设置模拟的子组件参数
您还可以创建一个模拟数据,其中比较不重要。我可以打个比方,假设你想用名字和姓氏对
人
对象进行排序。父比较器按名字排序,子比较器按姓氏排序。然后,您的模拟数据将是一个姓氏相同的人的列表。您的SomeParentComparator
很难独立测试,因为您直接在类对象的实例变量中初始化subComparator1
和subComparator2
我建议为这两个字段使用setter和getter,并使用setter或构造函数初始化它们
然后,您可以使用设置器
设置模拟的子组件参数
您还可以创建一个模拟数据,其中比较不重要。我可以打个比方,假设你想用名字和姓氏对人
对象进行排序。父比较器按名字排序,子比较器按姓氏排序。然后您的模拟数据将是一个姓氏相同的人的列表。理想情况下,您的所有类都将注入所有依赖项,而不是隐式的(在您的情况下,通过私有静态字段)。然而,在很多情况下,删除所有隐式依赖项会使代码过于复杂。在这种情况下,单元测试有两个选项:
构造单元测试运行程序,使依赖类的测试仅在依赖类的测试通过时运行
在单元测试期间,使用类似Powermock的方法绕过封装,并注入模拟的依赖项。这将允许依赖类的测试通过,即使依赖类被破坏
在您给出的示例中,我看不出为什么不能显式地表示依赖关系。字段不需要是静态的,因为该类的所有对象的行为方式都完全相同。因此,最好有一个“子比较器”的显式集合,并期望调用者显式地添加它们 理想情况下,所有类都将注入所有依赖项,而不是隐式的(在您的情况下,通过私有静态字段)。然而,在很多情况下,删除所有隐式依赖项会使代码过于复杂。在这种情况下,单元测试有两个选项:
构造单元测试运行程序,使依赖类的测试仅在依赖类的测试通过时运行
在单元测试期间,使用类似Powermock的方法绕过封装,并注入模拟的依赖项。这将允许依赖类的测试通过,即使依赖类被破坏
在您给出的示例中,我看不出为什么不能显式地表示依赖关系。字段不需要是静态的,因为该类的所有对象的行为方式都完全相同。因此,最好有一个“子比较器”的显式集合,并期望调用者显式地添加它们 我认为你误解了TDD的建议
实际上,您有两个可以独立测试的subcomparator类。然后是“父”比较器,它将子比较器的实例作为硬连线组件。只需分别测试它们。。。没有任何花哨的嘲弄
当然,父级的正确性取决于子比较程序的正确性。但是,由于前者和后者是不可分割的,因此为了测试的目的,将父对象视为一个黑盒子是更容易和更正确的
从另一个角度考虑,@ShanuGupta的回答建议您应该打破父比较器的抽象,允许模拟。大概您封装subcomparator实例是有充分理由的。现在您可以使用DI创建父构造函数。。。日分
@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)
(B,C)>(A,C)
(A,B)<(A,C)
(A,C)>(A,B)