對對象進行Assert

在單元測試中,當期望結(jié)果(Expect)和實際結(jié)果(Actual)都是對象時,進行Assert.assertEquals判斷時,可能會不符合預期,我們認為符合預期的測試結(jié)果還是失敗,
主要還是對象equals比較不等導致的。

原因分析

如果選用junit框架,當調(diào)用Assert.assertEquals(expected, actual),最終會
調(diào)用對象當equals方法:

private static boolean isEquals(Object expected, Object actual) {
        return expected.equals(actual);
    }

我們知道,Object是所有類的父類,其equals方法實現(xiàn)

public boolean equals(Object obj) {
        return (this == obj);
    }

這就引出另一個問題,equals如何比較,equals和=有何不同?
this 和 obj都是對象的引用,也就是對于任何非空的參考值x和y ,當且僅當x和y引用相同的對象( x == y具有值true )時,該方法返回true 。

解決方法

重寫對象的equals方法。參見jdk官方文檔,為了避免重寫equals方法引入該對象的其它操作漏洞,一定要實現(xiàn)等價關(guān)系。
public boolean equals(Object obj)

 equals方法在非空對象引用上實現(xiàn)等價關(guān)系:
 自反性 :對于任何非空的參考值x ,x.equals(x)應該返回true 。
 對稱性 :對于任何非空引用值x和y , x.equals(y)應該返回true當且僅當y.equals(x)回報true 。
 傳遞性 :對于任何非空引用值x , y和z ,如果x.equals(y)回報true個y.equals(z)回報true ,然后x.equals(z)應該返回true 。
 一致性 :對于任何非空引用值x和y ,多次調(diào)用x.equals(y)始終返回true或始終返回false ,沒有設(shè)置中使用的信息equals比較上的對象被修改。
 對于任何非空的參考值x , x.equals(null)應該返回false 。

請注意,無論何時覆蓋該方法,通常需要覆蓋hashCode方法,以便維護hashCode方法的通用合同,該方法規(guī)定相等的對象必須具有相等的哈希碼。

  hashCode的總合同是:
  只要在執(zhí)行Java應用程序時多次在同一個對象上調(diào)用該方法, hashCode方法必須始終返回相同的整數(shù),前提是修改了對象中equals比較中的信息。 該整數(shù)不需要從一個應用程序的執(zhí)行到相同應用程序的另一個執(zhí)行保持一致。
  如果根據(jù)equals(Object)方法兩個對象相等,則在兩個對象中的每個對象上調(diào)用hashCode方法必須產(chǎn)生相同的整數(shù)結(jié)果。
  不要求如果兩個對象根據(jù)equals(java.lang.Object)方法不相等,那么在兩個對象中的每個對象上調(diào)用hashCode方法必須產(chǎn)生不同的整數(shù)結(jié)果。 但是,程序員應該意識到,為不等對象生成不同的整數(shù)結(jié)果可能會提高哈希表的性能。
 盡可能多的合理實用,由類別Object定義的hashCode方法確實為不同對象返回不同的整數(shù)。 (這通常通過將對象的內(nèi)部地址轉(zhuǎn)換為整數(shù)來實現(xiàn),但Java的編程語言不需要此實現(xiàn)技術(shù)。)

哈希沖突是所有哈希函數(shù)無法完全避免的,只能盡量的減少沖突。所以也無法保證對于不同的對象,其hashCode完全不同。

具體實現(xiàn)

    @Builder @Setter @Getter
    public static class Tag extends Object {
        private Integer id;
        private String name;
        private float confidence;

        @Override
        public int hashCode() {
            return Objects.hash(this.id, this.name, this.confidence);
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == this) {
                return true;
            }

            if (obj == null) {
                return false;
            }
            Tag tag = (Tag) obj;
            if (tag.getId() == this.id
            && tag.getName().equals(this.name)
            && tag.getConfidence() == this.confidence) {
                return true;
            }
            return false;
        }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。