Collection-Based Matchers

Learn about DSL in ScalaTest by writing assertions on collections.

Collections

In this lesson, we’ll work with collections and collection-based assertions. We’ll start by extending our code a bit and implementing functionality to add and delete a course. When adding a course, we want its title to be unique. Similarly, we want to avoid duplicates when adding lessons and tags to a course. The latter can be achieved by replacing Seq with Set. The former is a bit trickier.

Press + to interact
sealed trait Course:
val title: String
val author: Author
val lessons: Set[Lesson]
val tags: Set[String]
case class FreeCourse(
override val title: String,
override val author: Author,
override val lessons: Set[Lesson],
override val tags: Set[String]
) extends Course
case class PaidCourse(
override val title: String,
override val author: Author,
override val lessons: Set[Lesson],
override val tags: Set[String]
) extends Course
class Educative(val courses: Seq[Course]):
def courseByName(courseTitle: String): Option[Course] = courses find (_.title == courseTitle)
infix def `with`(newCourse: Course): Either[String, Educative] =
courses find (_.title.equalsIgnoreCase(newCourse.title)) match
case Some(_) => Left(s"A course with title ${newCourse.title} already exists")
case None => Right(Educative(courses :+ newCourse))
infix def without(courseTitle: String): Educative = Educative(courses = courses filterNot (_.title.equalsIgnoreCase(courseTitle)))
def filterByTag(tag: String): Seq[Course] = courses filter (_.tags.exists(_.equalsIgnoreCase(tag)))

The Educative#with tag returns an Either[String, Educative], where the left projection (String) represents an error message and the right one (Educative) contains a new instance of the Educative platform with the new course if there’s no existing course with the same title. The implementation of Educative#without simply relies on Seq#filter to filter out a course with the same title. Note that Educative#without returns a copy of itself even if the course doesn’t exist.

We could have implemented it differently by returning this; however, that’s an implementation detail, and we won’t focus on it in this lesson. Both with and without are declared infix, so we can invoke them without . and (). In the snippet above, we also added a method to filter the courses by tag.

Plain assertions on collections

Before looking at some collection matchers, let’s see how we can use the plain old assert function to verify that our implementations of ...