我正在与同事就我遇到的特定情况进行辩论, 如果有人能提出一些观点或理论基础,那就太好了。
假设我们有 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可以服务, 但有人批评我们不想断言它们具有相同的值,只是调用了代码。
你怎么看?您对此有何看法?
最佳答案
答案实际上取决于您打算测试什么。基于此,答案会有所不同。
您是否测试传递的实例在
equals
方法报告的意义上是相同?如果是这样,那么verify(manager).f(givenA, "abc")
就足够了(假设您相信已经为给定的类实现了对象相等)。在大多数情况下,这是可取的,因为它在语义上更有意义,而且我们不想担心对象引用相等性等低级细节。在您上面的示例中,理想情况下,equals
方法应该是固定的:)您是否正在测试将相同的对象引用传递给该方法?在某些情况下,我们可能希望明确检查传递的对象是否确实是内部使用的相同引用,而不是被等效外观对象替换。这种情况很少见,但如果有这种需要,请使用
ArgumentCaptor
并断言发送值和捕获值之间的引用相等。
谈到您提到的那一点,我们不想断言它们具有相同的值,只是调用了代码。
我个人不同意断言方法已被调用就足够了。如果传递的值不同(如您提到的值)怎么办?这会使测试不完整并使代码变得脆弱。此类测试只会使覆盖率报告看起来绿色,但缺乏完整的功能覆盖率。
关于java - 正确的单元测试属性持有者没有平等的实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27909690/