我正在和一位同事就我遇到的特定情况进行辩论,如果有人能提出一些观点或理论基础,那就太好了。
假设我们有 A 类型的模型对象。他们是爪哇豆,财产持有者,并具有getPrice,getQuantity,getName等方法。
我们还假设出于某些遗留原因,equals 方法返回 true,在两个不同的对象上,即使它们具有不同的属性值!
我将提供一些代码来举例说明此问题。(显然不是相同的代码,采用快捷方式)
class A {
private final double q;
private final double p;
public A(double q, double p) {
this.q = q;
this.p = p;
}
public double getQuantity()
{
return q;
}
public double getPrice()
{
return p;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
// not the actual method but a.equals(aWithDifferentValues) is True
// this is the crux of the problem
return true;
}
}
public abstract class Handler {
protected Manager m;
public Handler(Manager m) {
this.m = m;
}
abstract public void handle(A a);
}
class HandlerA extends Handler {
public HandlerA(Manager m) {
super(m);
}
@Override
public void handle(A a) {
m.f(a, "abc");
}
}
...
class HandlerC extends Handler {
public HandlerC(Manager m) {
super(m);
}
@Override
public void handle(A a) {
m.g(a, 1);
}
}
class Manager {
public void f(A a, String s) { }
public void g(A a, double q) { }
}
我们要对处理程序 A 进行单元测试。
所以我们可能想写一个这样的测试:
public class TestMain {
@Test
public void givenA_fHappens() {
Manager manager = mock(Manager.class);
HandlerA handler = new HandlerA(manager);
A givenA = new A(7, 9);
handler.handle(givenA);
verify(manager).f(givenA, "abc");
}
}
现在的问题是,因为 equals 返回 true,对于具有不同属性的不同 A 对象,在代码中进行此修改:
@Override
public void handle(A a) {
-- m.f(a, "abc");
++ m.f(new A(1, 1), "abc");
}
单元测试不包括在内
我建议我们使用带有验证的匹配器(或断言有参数捕获器的地方)事实上,已经有一个名为SamePropertyValueAs的可以服务,但我遇到了批评,我们不想断言它们具有相同的值,只是调用了代码。
你觉得怎么样?您对此有何看法?
答案实际上取决于您要测试的内容。基于此,答案会有所不同。
-
您是否在测试通过的实例在
equals
方法报告的意义上是否相同?如果是这样,那么verify(manager).f(givenA, "abc")
就足够了(前提是您相信已经为给定类实现了对象相等)。在大多数情况下,这是可取的,因为它在语义上更有意义,我们不想担心低级细节,例如对象引用相等性。在上面的示例中,理想情况下,equals
方法应固定:) -
您是否正在测试是否将相同的对象引用传递给该方法?在某些情况下,我们可能希望显式检查传递的对象是否确实与内部使用的引用相同,而不是被等效的对象替换。这种情况相当罕见,但如果有这样的需求,请使用
ArgumentCaptor
并断言发送值和捕获值之间的引用相等性。
到了你提到的这一点,我们不想断言它们具有相同的值,只是调用了代码。
就我个人而言,我不同意断言调用该方法就足够了。如果传递的值不同(如您提到的值),该怎么办?这将使测试不完整并使代码变脆。此类测试只能使覆盖率报告看起来绿色,但缺乏完整的功能覆盖率。