【问题标题】:Correct unit testing property holder with no equals implementation正确的单元测试属性持有者没有相等的实现
【发布时间】:2023-03-24 12:57:01
【问题描述】:

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

假设我们有类型 A 的模型对象。它们是 java bean、属性持有者、 并拥有 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) { }
}

我们要对 HandlerA 进行单元测试。

所以我们可能想写一个这样的测试:

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

你怎么看?您对此有何看法?

【问题讨论】:

    标签: java unit-testing tdd mockito hamcrest


    【解决方案1】:

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

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

    2. 您是否在测试是否将相同的对象引用传递给该方法?在某些情况下,我们可能想要明确地检查传递的对象是否确实与内部使用的引用相同,并且没有被看起来 等效 的对象替换。这种情况很少见,但如果有这种需要,请使用ArgumentCaptor 并声明发送值和捕获值之间的引用相等。

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

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

    【讨论】:

    • 感谢您的回答。对象和值不应改变。这只是对正确代码的调度逻辑。 IMO 我们应该验证该对象是否仍然具有相同的值。对此有更多的看法会有所帮助
    猜你喜欢
    • 1970-01-01
    • 2015-03-03
    • 1970-01-01
    • 1970-01-01
    • 2015-01-05
    • 2011-01-15
    • 2015-04-10
    • 2017-08-23
    • 1970-01-01
    相关资源
    最近更新 更多