Bill Turner
Bill Turner

Reputation: 879

scala test fails though actual appears to match expected

I am taking the Coursera course Functional Programming in Scala. If you have qualms about providing the solutions to problems, this does not pertain directly to the assignment.

I am finding myself frequently unclear about what is happening. So, I use tests to gain insight. In the assignment for the current week a set of tests are included. In the suite of tests a couple functions are defined - size and asSet, the latter of which converts a TweetSet to Set[Tweet]. I created tests for both. The size tests work just fine. The asSet works for the empty set, but it fails with a set of one element. The output message sure makes it seem like what I have done is correct, so I have no idea at present what is wrong.

The result message is:

org.scalatest.exceptions.TestFailedException: Set(User: a
Text: a body [20]) did not equal Set(User: a
Text: a body [20])

As you can see, it states that the result is equal to the expect. Here is the failing test:

  test("asSet: on singleton set") {
    new TestSets {
        assert(asSet(set2) === Set[Tweet](new Tweet("a", "a body", 20)))
    }
  } 

The function is defined as follows (this was provided in the course materials):

  def asSet(tweets: TweetSet): Set[Tweet] = {
    var res = Set[Tweet]()
    tweets.foreach(res += _)
    res
  }

The definition of set2 as follows (again, provided):

val set1 = new Empty
val set2 = set1.incl(new Tweet("a", "a body", 20))

Tweet is defined as follows:

class Tweet(val user: String, val text: String, val retweets: Int) {
  override def toString: String =
    "User: " + user + "\n" +
    "Text: " + text + " [" + retweets + "]"
}

What am I missing such that this test is failing though looks like it should be passing?

Upvotes: 2

Views: 1702

Answers (2)

Zoltán
Zoltán

Reputation: 22206

I believe your problem is that in the assignment you are manually developing an implementation of Set, whereas on the other hand you used Scala's internal Set type to compare it to; i.e. you are comparing two instances of different types.

I believe the right-hand side of this line creates a scala.collection.immutable.Set

assert(asSet(set2) === Set[Tweet](new Tweet("a", "a body", 20)))

Upvotes: 0

Andreas Neumann
Andreas Neumann

Reputation: 10904

Your test fails because of the way hashCode is implemented.

  • To compare with == Scala uses the equals method which is implemented on every class.
  • To determine if a instance is contained in a Set or to use it as key Scala uses the hashCode method

The basic source of your error As you have implemented Tweet every instance is different, even if it contains the same information.

scala> val x= Set(new Tweet( "me", "test message", 1),new Tweet( "me", "test message", 1) )
  x: scala.collection.immutable.Set[Tweet] =
  Set(User: me
      Text: test message [1 ],
      User: me
      Text: test message [1 ])

 scala> x.size
 res3: Int = 2

How this methods are implemented differs with classes and case classes.

Example

with normal class

class Tweet(val user: String, val text: String, val retweets: Int) {
  override def toString: String = 
    s"""User: $user
    |Text: $text [$retweets ]""".stripMargin
}



scala> val x = new Tweet( "me", "test message", 1)
x: Tweet =
  User: me
  Text: test message [1 ]

scala> x == x
res0: Boolean = true

scala> x == new Tweet( "me", "test message", 1)
res1: Boolean = false

with case class

case class Tweet(val user: String, val text: String, val retweets: Int) {
   override def toString: String = 
   s"""User: $user
       |Text: $text [$retweets ]""".stripMargin
}

scala> val x = new Tweet( "me", "test message", 1)
x: Tweet =
  User: me 
  Text: test message [1 ]

scala> x == x
res2: Boolean = true

scala> x == new Tweet( "me", "test message", 1)
res3: Boolean = true

scala> (new Tweet( "me", "test message", 1)).hashCode
res6: Int = -1967705983

scala> (new Tweet( "me", "test message", 1)).hashCode
res7: Int = -1967705983

Upvotes: 1

Related Questions