正确的单元测试属性持有者,没有相等的实现



我正在和一位同事就我遇到的特定情况进行辩论,如果有人能提出一些观点或理论基础,那就太好了。

假设我们有 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的可以服务,但我遇到了批评,我们不想断言它们具有相同的值,只是调用了代码。

你觉得怎么样?您对此有何看法?

答案实际上取决于您要测试的内容。基于此,答案会有所不同。

  1. 您是否在测试通过的实例在equals方法报告的意义上是否相同?如果是这样,那么verify(manager).f(givenA, "abc")就足够了(前提是您相信已经为给定类实现了对象相等)。在大多数情况下,这是可取的,因为它在语义上更有意义,我们不想担心低级细节,例如对象引用相等性。在上面的示例中,理想情况下,equals方法应固定:)

  2. 您是否正在测试是否将相同的对象引用传递给该方法?在某些情况下,我们可能希望显式检查传递的对象是否确实与内部使用的引用相同,而不是被等效的对象替换。这种情况相当罕见,但如果有这样的需求,请使用ArgumentCaptor并断言发送值和捕获值之间的引用相等性。

到了你提到的这一点,我们不想断言它们具有相同的值,只是调用了代码

就我个人而言,我不同意断言调用该方法就足够了。如果传递的值不同(如您提到的值),该怎么办?这将使测试不完整并使代码变脆。此类测试只能使覆盖率报告看起来绿色,但缺乏完整的功能覆盖率。

相关内容

  • 没有找到相关文章