...

/

Testing Private Methods and Nested Properties

Testing Private Methods and Nested Properties

Learn how to make more fine-grained assertions targeting private and nested properties of a class.

We'll cover the following...

Now that we’ve discussed some best practices in ScalaTest, it’s time to explore more syntactic sugar. We’ll start by looking at how we can test nested properties and private methods.

Nested properties

The simplest way to check for nested properties is to rely on direct access. For example, assume we wanted to validate all the properties of a Course.

package mdipirro.educative.io.effectiveunitandintegrationtestinginscala.matchers

import mdipirro.educative.io.effectiveunitandintegrationtestinginscala.TestSuite
import mdipirro.educative.io.effectiveunitandintegrationtestinginscala.model.v2.{Author, Educative, FreeCourse, Lesson}

class EducativeSpec extends TestSuite:

  private val educative = Educative(Seq(
    FreeCourse("Scala for Beginners", Author("John", "Doe"), Set.empty[Lesson], Set.empty[String]),
    FreeCourse("Scala for Data Analysis", Author("Mary", "Jane"), Set.empty[Lesson], Set("Scala")),
    FreeCourse("Functional Kotlin", Author("Mary", "Jane"), Set.empty[Lesson], Set("kotlin"))
  ))

  "The Educative platform" `should` "return a valid course, if it exists" in {
    val c = educative.courseByName("Scala for Beginners").get

    c.title shouldBe "Scala for Beginners"
    c.author.firstName shouldBe "John"
    c.author.lastName shouldBe "Doe"
    c.lessons shouldBe empty
    c.tags shouldBe empty
    c.price shouldBe 0
  }
Testing nested properties of a class

Ignore for now the .get invoked on the Option[Course] returned by Educative#courseByName (line 15). The example above asserts the expected value for each property of Course. There are more idiomatic ways, such as pattern matching.

package mdipirro.educative.io.effectiveunitandintegrationtestinginscala.matchers

import mdipirro.educative.io.effectiveunitandintegrationtestinginscala.TestSuite
import mdipirro.educative.io.effectiveunitandintegrationtestinginscala.model.v2.{Author, Educative, FreeCourse, Lesson, PaidCourse}

class EducativeSpec extends TestSuite:

  private val educative = Educative(Seq(
    FreeCourse("Scala for Beginners", Author("John", "Doe"), Set.empty[Lesson], Set.empty[String]),
    FreeCourse("Scala for Data Analysis", Author("Mary", "Jane"), Set.empty[Lesson], Set("Scala")),
    FreeCourse("Functional Kotlin", Author("Mary", "Jane"), Set.empty[Lesson], Set("kotlin"))
  ))

  "The Educative platform" `should` "return a valid course, if it exists" in {
    educative.courseByName("Scala for Beginners").get match
      case fc@FreeCourse(title, Author(firstName, lastName), lessons, tags) =>
        title shouldBe "Scala for Beginners"
        firstName shouldBe "John"
        lastName shouldBe "Doe"
        lessons shouldBe empty
        tags shouldBe empty
        fc.price shouldBe 0
      case PaidCourse(_, _, _, _) => fail("Expecting a FreeCourse, got a PaidCourse")
  }
Testing nested properties of a case class via pattern matching

Pattern matching usually makes the code clearer, but in this case, it adds some boilerplate. Not only do we have to explicitly fail the PaidCourse match, but we also have to give a name to the matched FreeCourse (fc in the example above) to check fc.price. Furthermore, by destructuring Author as well, we flatten all the properties because now it’s less clear that firstName and lastName ...