簡體   English   中英

正確的單元測試屬性持有者,不等於實現

[英]Correct unit testing property holder with no equals implementation

我正在與一位同事就我遇到的特定情況進行辯論,如果有人可以出於某種觀點或理論基礎而陷入困境,那將是非常棒的。

假設我們有一個類型為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並聲明已發送值和捕獲值之間的引用相等性。

到您提到的地步, 我們不想斷言它們具有相同的值,只需要調用代碼即可

我個人並不認為斷言該方法已被調用就足夠了。 如果傳遞的值不同(如您提到的值),該怎么辦。 這會使測試不完整並使代碼變脆。 這樣的測試只會使覆蓋率報告看起來綠色,但缺乏完整的功能覆蓋率。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM