java - 正确的单元测试属性持有者没有平等的实现

标签 java unit-testing tdd mockito hamcrest

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

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

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

最佳答案

答案实际上取决于您打算测试什么。基于此,答案会有所不同。

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

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

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

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

关于java - 正确的单元测试属性持有者没有平等的实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27909690/

相关文章:

java - 在 for 循环中更新列表值失败但在具有对象值的列表中成功

java - 根据用户输入显示乘法表

java - 没有父pom.xml的spring-boot无法生成war打包

php - 如何在 PHP Mockery 中执行 hasKeys() 或创建自定义参数期望?

swift - Swift 中的测试驱动开发

c# - 使用 TDD 和 C# 设计的开源项目?

java - 将图像上传到 Google Cloud Storage (Java)

python - 在 SQLAlchemy 应用程序的单元测试中使用 Alembic?

unit-testing - 在维护测试套件时,所有 'errors' 最终都应该变成 'failures' 吗?

unit-testing - 用spock另一个域类创建的模拟域类