2015-10-28 38 views
0

我有關於在Matchers中使用FunSuite的問題。Scala FunSuite在比較列表時出現「應該是」和「===」之間的區別

我試圖讓我試着這樣做要比較的對象列表:

orders2 should be(tiOrdersList2) 

其中ORDERS2和tiOrdersList2是scala.List [MyObject來]

本場比賽悲慘的失敗了,所以我嘗試與

orders2.toSeq should be (tiOrdersList2.toSeq) 

沒有運氣

然後我試圖匹配SINGL Ë項目

orders2(0) should be (tiOrdersList2(0)) 

末沒有運氣再次

我發現,要使它成爲一個對象,我不得不使用「===」,並要回我設法拿到了第一種情況下工作這工作:

orders2 === tiOrdersList2 

我不明白這裏有什麼區別。 我認爲「應該是」匹配比「===」嚴格,但我看不出爲什麼。 任何人都可以解釋給我?

注意:我想指出MyObject具有不同的基於Java的類型的各種屬性,包括float。可能是這個原因嗎?

UPDATE 我查了一下簡單的類匹配(見下文片斷),如果我覆蓋了equals方法對我自己,也「應爲」的作品,所以主要問題是一種比較的是什麼「 ===「幹嘛?

import org.scalatest.{Matchers, FunSuite} 
import org.junit.runner.RunWith 
import org.scalatest.junit.JUnitRunner 

@RunWith(classOf[JUnitRunner]) 
class blahSuite extends FunSuite with Matchers 
{ 
    test("extractSessions") { 
     new Object1 === (new Object1) 
     new Object2 === (new Object2) 
     new Object1 shouldEqual (new Object1) 
     new Object2 should be (new Object2) 
    } 

    class Object1 { 
     val pippo: java.lang.String = "blah" 
     val pappo:java.lang.Long = 0l 
     override def toString(): String = { 
      s"$pippo, $pappo" 
     } 
    } 
    class Object2 { 
     val pippo: java.lang.String = "blah" 
     val pappo:java.lang.Long = 0l 
     val pluto:java.lang.Float = 0.0f 
     override def toString(): String = { 
      s"$pippo, $pappo, $pluto" 
     } 
    } 
} 

UPDATE2 似乎「===」比較非常鬆散:我試着用其他情況,即對象的內容是不同的(即不同的「皮波」的字符串),它告訴我,他們是一樣。 所以它似乎比較類的類型,而不是做一些反思的魔術... 我越來越多的困惑,並開始認爲我應該實現我的等同方法,忘掉這個...

+0

也許他們排序不同,等於檢查是錯誤的,因爲它? –

+0

nope,我也試過在單個對象上做它。即使通過打印內容(我實現了一些toString方法)來檢查這些集合,並使用調試器查看每個對象。 – gmconte

+0

您可以添加失敗的特定測試嗎?在第一次更新中提到的那些沒有描述你在原始問題中討論的列表/序列。或者,您是否將您的問題縮小到只針對Object1和Object2? –

回答

2

關於===

我覺得===不完全是你的想法。你應該使用assert(1 === 4)。正如scalatest doc指出:

ScalaTest讓你使用Scala的聲明語法,而是定義了一個三元 等於運算符(===)以得到更好的錯誤訊息。下面 代碼會給你僅指示某個斷言失敗的錯誤:

assert(1 == 2) 

使用三重等號,而不是會給你更多的 錯誤提示信息,「1不等於2」:

assert(1 === 2) 

所以=====相同。

(請注意,您也可以在像result should === (3)的匹配===作爲docs提及,但我不認爲這是真的對你很重要,現在,就是讓你知道他們是不同的東西)

應該是(工作?)

Should be是不是也工作。問題在於第一個失敗的斷言(shouldEqual)引發錯誤並且執行停止,所以我們從未運行過should be。如果您更改順序,你會看到錯誤should be也:

new Object2 should be (new Object2) 
new Object1 shouldEqual (new Object1) 

[info] - extractSessions *** FAILED *** 
[info] blah, 0, 0.0 was not equal to blah, 0, 0.0 (testa.scala:22) 

比較

正如你已經找到答案,我們不能只比較對象:

val a = new Object1 
val b = new Object1 

println(a == b) // false 

// Or the equivalent version 

println(a.equals(b)) // false 

粗略地說,當你打電話給==時你實際上是這樣稱呼的:

println(a.hashCode == b.hashCode) // false 

而且由於的hashCode的缺省實現是基於當前對象的內存地址,但他們都沒有明顯不一樣:

println(a.hashCode) // 769724695 
println(b.hashCode) // 757278160 

所以,是的,你將不得不...

重新實現equals和hashCode

什麼樣的事情在這個Scala Cookbook recipe做,你可以做這樣的事情:

test("extractSessions") { 
    new Object3 should be (new Object3) 
    new Object3 shouldEqual (new Object3) 
} 

class Object3 { 
    // PS: A little code improvement: 
    // I removed the old ugly, java like 
    // val pippo: java.lang.String = "blah" 
    // with the more scala-like: 
    val pippo = "blah" // Scala guesses the type -> String 
    val pappo = 0L  // again -> Long 

    def canEqual(a: Any) = a.isInstanceOf[Object3] 

    override def equals(that: Any): Boolean = 
    that match { 
     case that: Object3 => that.canEqual(this) && this.hashCode == that.hashCode 
     case _    => false 
    } 

    override def hashCode: Int = (41 * (41 + pippo.hashCode) + pappo.hashCode) 
} 

所以...我總是必須重新實現hashCode,並等於我的對象。這是它嗎?就這樣?

不!

斯卡拉可以爲你做更多!

此案類

當你之前類定義使用關鍵字case創建case class。這和其他不錯的功能一起爲您自動實現hashcode,equalstoString方法。

所以,現在,我們可以有這樣的事情:

// ... 

test("extractSessions") { 
    assert(Object1("blah", 0L) === Object1("blah", 0L)) 
    assert(Object2("blah", 0L, 0.0F) === Object2("blah", 0L, 0.0F)) 

    Object1("blah", 0L) shouldEqual (Object1("blah", 0L)) 
    Object2("blah", 0L, 0.0F) should be (Object2("blah", 0L, 0.0F)) 

    // Also works 
    new Object1("blah", 0L) shouldEqual (new Object1("blah", 0L)) 
} 

case class Object1(pippo: String, pappo: Long) 

case class Object2(pippo: String, pappo: Long, pluto: Float) 

// ...  

如果你真的想要去更深,想更深刻地理解了平等的解決方案和陷阱,我推薦文章How to Write an Equality Method in Java從馬丁Odersky的到理解Java中的一些平等問題。這有助於理解爲什麼有些事情是他們在Scala中的方式。

+0

謝謝Onilton。 「應該」的解釋是非常有用的,並澄清了爲什麼我的例子不起作用。我仍然對「===」有所懷疑:正如你所提到的,除了具有更多的細節和做比較深的「==」調用以便比較對象是數組之外,它與「==」相同。我附加了另一個例子,其中「==」返回true,即使我沒有case類或hashcode/equals覆蓋。你有什麼想法爲什麼「==」返回true? – gmconte

+0

對不起,我只是重新測試和仔細閱讀您的答案,並理解爲「==」的情況下,我的問題是沒有添加「斷言」之前檢查。現在都清楚了。謝謝! – gmconte

相關問題