2015-08-27 24 views
6

我正在爲代碼學校的一個項目進行單元測試,.equals()給我帶來一些麻煩。在我的項目中,.save()正在保存到SQL數據庫中。此代碼傳遞單元測試:爲什麼在比較兩個對象時,.equals()會導致斷言錯誤...但只是有時會出現?

@Test 
public void save_assignsNameToObject() { 
    Restaurant testRestaurant = new Restaurant("PokPok","503-444-4444"); 
    testRestaurant.save(); 
    Restaurant savedRestaurant = Restaurant.all.get(0); 
    assertEquals(savedRestaurant.getName(), "PokPok"); 
} 

但是,如果我改變最終行到下文中,將導致斷言錯誤:

assertTrue(savedRestaurant.equals(testRestaurant)); 

我調試使用System.out.println()來驗證這兩個值testRestaurant做「.equal」savedRestaurant中的對應值。下面的單元測試(關於另一對象,非常類似於類)通過使用.equals()方法:

@Test 
public void save_assignsIdToObject_true() { 
    Cuisine testCuisine = new Cuisine("Mexican"); 
    testCuisine.save(); 
    Cuisine savedCuisine = Cuisine.all().get(0); 
    assertTrue(savedCuisine.equals(testCuisine)); 
} 

編輯:這裏是.equals()我的源代碼:

@Override 
public boolean equals(Object otherRestaurant) { 
    if (!(otherRestaurant instanceof Restaurant)) { 
    return false; 
    } else { 
    Restaurant newRestaurant = (Restaurant) otherRestaurant; 
    return this.getId() == new Restaurant.getId() && 
      this.getName().equals(newRestaurant.getName()) && 
      ... 
      this.getPhone().equals(newRestaurant.getPhone()); 
    } 
    } 

爲什麼.equals()比較一些對象而不是其他人?在我的代碼示例中,我看到的唯一區別是一個對象接受一個參數,另一個接受兩個參數。

謝謝!

+0

我想你應該向我們展示你爲'Restaurant'類重寫的'equals'方法。 – wawek

+0

你可以向我們展示'美食'類嗎? –

+0

@HollaHexkey引用我更新的答案。 –

回答

3

默認情況下,equals()上的Java對象的檢查它們是完全相同的對象(未兩個對象具有相同的值) 。 http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals%28java.lang.Object%29

String對象重寫equals()以給出一個版本,它將爲具有相同值的兩個不同對象返回true,但您的自定義Restaurant類不會。

您可以定義自定義equals()

public class Restaurant { 

    private String name; 
    private String tel; 

    public Restaurant(String name, String tel) { 
    this.name = name; 
    this.tel = tel; 
    } 

    /*getters and setters*/ 

    override public boolean equals(Object obj) { 
    if(obj instanceOf Restaurant) { 
     Restaurant that = (Restaurant) obj; 
     return (this.name.equals(that.getName()) && this.tel.equals(that.getTel())); 
    } else { 
     return false; 
    } 
    } 
} 
+0

感謝您的幫助。即使對於Restaurant重寫equals(),上面的代碼仍然會導致斷言錯誤。在我的斷言中有什麼我應該改變的?我聲明變量並在你的例子中引用構造函數中的對象。 –

+0

Downvoted在您的示例中未實現hashCode。 –

1

第一次比較StringssavedRestaurant.getName())其中第二次比較類RestaurantsavedRestaurant)的對象。

字符串有自己的執行equals()方法。

您需要重寫equals方法Restaurant才能使您的期望值相等,否則會檢查兩個對象是否完全相同(object.equals())。


更新:

你有問題,這條線在你的equals方法

如果id爲long

this.getId() == newRestaurant.getId() // not new Restaurant.getId() 

如果id爲Long

this.getId().equals(newRestaurant.getId()) // not new Restaurant.getId() 
+0

操作問爲什麼assertTrue(savedRestaurant.equals(testRestaurant));沒有工作和assertTrue(savedCuisine.equals(testCuisine));工作 –

+0

@ErwanC。,我明白了。我要求OP展示'Cuisine'類。 –

+0

感謝您的意見。我忽略了之前提到我的equals()覆蓋(固定)。美食課很長。它的格式與上面的@mattinbits代碼完全一樣。這有幫助嗎? –

1

默認情況下,您的Restaurant.equals()回落到Object.equals(),它只比較對象標識符。當你打電話給Restaurant.all.get(0)時,你顯然回到了Restaurant的不同實例。字段值是相同的,但它是一個不同的對象實例。

我不建議執行equals()hashCode(),因爲這是很難得到正確的,這裏不需要。我只是給每個班級一個ID字段,通常是long值,它映射到數據庫中的自動增量字段。該ID唯一標識數據庫中的每條記錄。然後在你的測試中,你可以簡單地檢查你是否得到了具有相同數據庫ID的對象。

行爲目前與CuisineRestaurant不同的原因可能在於您未向我們展示的代碼。也許他們使用equals()的不同實現?或者他們保存和檢索工作的方式不同?也許Cuisine.get()返回與保存的對象實例相同的對象實例,並且Restaurant.get()會創建一個新實例?爲了讓我們知道你必須展示兩個類的代碼。

您是否在使用內存數據庫?你如何存儲RestaurantCuisine數據?

+0

感謝您的幫助。美食和餐廳的工作幾乎完全相同,並且具有幾乎相同的代碼(包括等於),但餐廳根據其所屬的美食類別從數據庫中提取美食ID的情況除外。 –

1

你需要重寫的實施等於餐廳類是能夠使用它與正確的感覺來比較類

默認值等於比較會導致你的方法的對象對象類,如果兩個對象指向相同的附圖(在存儲器中同一地址),其只檢查的

+0

儘量避免重寫equals(),但如果你這樣做,你也必須重寫hashCode() –

+0

@AdriaanKoster,你說得對,我們應該重寫'equals()'時重寫'hashCode()',但是這個OP的問題與'hashCode()'方法無關。 –

+0

這是一個討厭的bug的常見來源,所以它不能被忽略。 –

相關問題