Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a HavePropertyMatcher for collection elements in ScalaTest?

I've been using ScalaTest's FeatureSpec for a couple of days now and I'm trying to understand if it's possible to define the following spec using the built-in matchers (and if not, how I can write a suitable custom matcher).

Suppose I have the class Book:

case class Book(val title: String, val author: String)

and in my test I have a List of books:

val books = List(Book("Moby Dick", "Melville"))

Now, I would like to specify that the books list should contain a book with the title "Moby Dick". I would like to write something like:

books should contain (value with title "Moby Dick")  

I can't seem to figure out from the docs and code if it's possible to express this requirement in ScalaTest. Has anyone ran into a similar situation?

like image 394
Ori Avatar asked Aug 09 '11 14:08

Ori


People also ask

What is FlatSpec in Scala?

The main premise behind the FlatSpec trait is to help facilitate a BDD style of development. It's named flat because the structure of the tests we write is unnested in nature. In addition, this trait tries to guide us into writing more focused tests with descriptive, specification-style names.

What is shouldBe in Scala?

option shouldBe defined. If you mix in (or import the members of) OptionValues , you can write one statement that indicates you believe an option should be defined and then say something else about its value. Here's an example: import org.scalatest.OptionValues._ option.value should be < (7)


1 Answers

In the meantime here's a custom matcher you can use:

def containElement[T](right: Matcher[T]) = new Matcher[Seq[T]] {
  def apply(left: Seq[T]) = {
    val matchResults = left map right
    MatchResult(
      matchResults.find(_.matches) != None,
      matchResults.map(_.failureMessage).mkString(" and "),
      matchResults.map(_.negatedFailureMessage).mkString(" and ")
    )
  }
}

Then you can use the full power of the ScalaTest Have matcher to inspect the fields of your object:

val books = List(Book("Moby Dick", "Melville"),
                 Book("Billy Budd", "Melville"), 
                 Book("War and Peace", "Tolstoy"))

books should containElement(have('title("Moby Dick")))
books should containElement(have('title("Billy Budd"), 'author("Melville")))
books should containElement(have('title("War and Peace"), 'author("Melville")))

The last one is a failure producing this output:

The title property had value "Moby Dick", instead of its expected value "War and Peace", on object Book(Moby Dick,Melville) and The title property had value "Billy Budd", instead of its expected value "War and Peace", on object Book(Billy Budd,Melville) and The author property had value "Tolstoy", instead of its expected value "Melville", on object Book(War and Peace,Tolstoy)

You can also combine matchers with and or or, use not, etc.

like image 165
ryryguy Avatar answered Sep 29 '22 11:09

ryryguy