Adding Human-Readable Information
Learn how to print debug information in the test case and generate coverage reports.
Log messages
We’ve met many different ScalaTest tools so far, allowing us to assert a wide range of properties using two testing styles (assertions and matchers). However, we haven’t focused on log messages. Log messages are also very important for testing code, although not as important in applicative code. Our tests do complex operations and assert many properties, so logging information can be useful. Also, we can display information to clarify what’s being done during the test.
We can do that in three ways. The most obvious is using println
statements. It works but fits poorly in the test output, as we’ll see shortly. ScalaTest offers two better ways: Informers
and GivenWhenThen
. In this lesson, we’ll explore these three ways.
The println
statements
The most basic way of printing information during the execution of our tests is by using println
statements. The following example retrofits the EducativeSpec
class, adding println
statements.
package mdipirro.educative.io.effectiveunitandintegrationtestinginscala.info 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")) )) "Educative" `should` "delete more than one course" in { println("Attempting to delete all courses from the Educative platform") val ed = educative without "scala for beginners" without "Scala for Data Analysis" without "functional Kotlin" println("Checking the Educative platform is not empty") ed.courses shouldBe empty } it `should` "not delete the course if there's no course with the same title" in { println("Attempting to delete a course from the Educative platform") val ed = educative without "Scala for Absolute Beginners" println("Checking the Educative platform contains some other courses") ed.courses should not be empty println("Checking the course was not deleted") ed.courses should contain theSameElementsAs educative.courses }
Note that we added several println
statements describing in detail what’s happening in the test. If we run EducativeSpec
, we’ll get the following output:
testOnly mdipirro.educative.io.effectiveunitandintegrationtestinginscala.info.EducativeSpecAttempting to delete all courses from the Educative platformChecking the Educative platform is not emptyAttempting to delete a course from the Educative platformChecking the Educative platform contains some other coursesChecking the course was not deleted[info] EducativeSpec:[info] Educative[info] - should delete more than one course (2 milliseconds)[info] - should not delete the course if there's no course with the same title (1 millisecond)[info] Run completed in 18 milliseconds.[info] Total number of tests run: 2[info] Suites: completed 1, aborted 0[info] Tests: succeeded 2, failed 0, canceled 0, ignored 0, pending 0[info] All tests passed.[success] Total time: 1 s, completed Feb 28, 2023, 5:17:57 PM[IJ]
As you can see, the output is a mess. It’s unclear where the messages come from; they all appear before the test description printed by ScalaTest. This is why println
shouldn’t be used to display runtime information about our tests.
Let’s assume that we incorrectly asserted ed.courses shouldBe empty
in the second test case (line 26). The println
statements after the unsatisfied ...