ScalaTest and Cheatsheet

By Nadim Bahadoor | Last updated: May 8, 2019 at 6:58 am

In this section, we will show small code snippets and answers to common questions. So let's get started!

ScalaTest:

Collection:

General:

Futures:

 

ScalaTest Introduction

ScalaTest is a popular framework within the Scala eco-system and it can help you easily test your Scala code. As per the official ScalaTest documentation, ScalaTest is simple for Unit Testing and, yet, flexible and powerful for advanced Test Driven Development.

 

ScalaTest provides various flavours to match your test style and in the examples below we will be using FlatSpec. You can find in-depth code snippets on assertions and matchers from the official ScalaTest FlatSpec documentation.

 

For additional details on the other test styles such as FunSpec, WordSpec, FreeSpec, PropSpec and FeatureSpec, please refer to the official ScalaTest documentation.

 

Add ScalaTest as dependency to build.sbt

In order to use ScalaTest, you will need to add the dependencies in your build.sbt file as shown below. If you are unsure about adding external libraries as dependencies to build.sbt, you can review our tutorial on SBT Depedencies.


libraryDependencies ++= Seq("org.scalatest" %% "scalatest" % "3.0.1" % Test)

 

Create a test class using FlatSpec and Matchers

Let's assume that we have a class called DonutStore and we would like to create a test class for it. Using ScalaTest, you can create a test class by extending org.scalatest.FlatSpec. In your test class, you would typically have a series of assertions, which we will show in the next tutorial. As such you can also add the trait org.scalatest.Matchers.


class Tutorial_01_DonutTest extends FlatSpec with Matchers {

  behavior of "DonutStore class"

}

 

Equality Test

Assume we have a method named favouriteDonut() in a DonutStore class, which returns the String name of our favourite donut. We can create a test case for the favouriteDonut() method using ScalaTest's equality matchers as shown below.

 

In IntelliJ, to run our test class Tutorial_02_Equality_Test, simply right click on the test class and select Run Tutorial_02_Equality_Test.

 

If you are just getting started with ScalaTest, you can review the previous tutorials for adding ScalaTest dependency in your build.sbt, and extending the FlatSpec class with the Mathers trait.


class Tutorial_02_Equality_Test extends FlatSpec with Matchers {
  behavior of "DonutStore class"

  "favourite donut" should "match vanilla donut" in {
    val donutStore = new DonutStore()
    donutStore.favouriteDonut() shouldEqual "vanilla donut"
    donutStore.favouriteDonut() === "vanilla donut"
    donutStore.favouriteDonut() should not equal "plain donut"
    donutStore.favouriteDonut() should not be "plain donut"
    donutStore.favouriteDonut() !== "Plain donut"
  }
}

// The DonutStore class which we are testing using ScalaTest
class DonutStore {
  def favouriteDonut(): String = "vanilla donut"
}

 

Length Test

Throughout your program, you may be capturing list of items into Scala's Collection data structures. For instance, we'll go ahead and update our DonutStore class with a donuts() method, which will return an Immutable Sequence of type String representing donut items.


class DonutStore {
  def favouriteDonut(): String = "vanilla donut"

  def donuts(): Seq[String] = Seq("vanilla donut", "plain donut", "glazed donut")
}

Using ScalaTest's length and size matchers, you can easily create tests for collection data types. As such, you can test that our donuts() method would always return a Sequence of type String whose length is equal to 3 donut items from the code snippet below.


class Tutorial_03_Length_Test extends FlatSpec with Matchers {

  "Length and size of donuts" should "be equal to 3" in {
    val donutStore = new DonutStore()
    val donuts = donutStore.donuts()
    donuts should have size 3
    donuts should have length 3
  }
}

To run your test class Tutorial_03_Length_Test in IntelliJ, simply right click on the test class and select Run Tutorial_03_Length_Test.

 

Boolean Test

In the previous example, we showed how to use ScalaTest's length and size matchers to write length tests such testing the number of elements in a collection. ScalaTest matchers also comes with handy ===, shouldEqual and should methods, which you can use to write boolean tests.

 

For instance, you may test that a certain element exists in a collection or a collection is not empty. The code below illustrates some of the Boolean tests using ScalaTest's matchers.


  "Examples of boolean assertions" should "be valid" in {
    val donutStore = new DonutStore()
    val donuts = donutStore.donuts()
    donuts.nonEmpty shouldEqual true
    donuts.size === 3
    donuts.contains("chocolate donut") shouldEqual false
    donuts should not be empty
    donutStore.favouriteDonut() should not be empty
  }

 

For the purpose of this boolean test, we are reusing the DonutStore class from the previous Length test:


class DonutStore {
  def favouriteDonut(): String = "vanilla donut"

  def donuts(): Seq[String] = Seq("vanilla donut", "plain donut", "glazed donut")
}

Similar to the previous ScalaTest examples, right click on the test class Tutorial_04_Boolean_Test and select Run to run the test within IntelliJ.

 

Collection Test

So far, we've introduced ScalaTest Equality, Length and Boolean tests using ScalaTest's matchers. In this section, we'll present how you can use ScalaTest's matchers to write tests for collection types by using should contain, should not contain or even shouldEqual methods.

 

As an example, the code below shows how to test that an element exists, or not, within a collection type (in our case, a donut Sequence of type String).


  "Examples of collection assertions" should "be valid" in {
    val donutStore = new DonutStore()
    val donuts = donutStore.donuts()
    donuts should contain ("plain donut")
    donuts should not contain "chocolate donut"
    donuts shouldEqual Seq("vanilla donut", "plain donut", "glazed donut")
  }

As a reminder, our DonutStore class for this Collection Test is similar to our previous examples as follows:


class DonutStore {
  def favouriteDonut(): String = "vanilla donut"

  def donuts(): Seq[String] = Seq("vanilla donut", "plain donut", "glazed donut")
}

By now, you should be familiar how to run the test, by right clicking on the test class Tutorial_05_Collection_Test and select the Run menu item within IntelliJ.

 

Type Test

Let's continue our journey into learning how to test your Scala classes by using the popular ScalaTest library. In this section, we'll present how you can use ScalaTest's should be a method to easily test certain types, such as a String, a particular collection or some other custom type.

 

We'll use our DonutStore example, and test that a DonutStore value should be of type DonutStore, the favouriteDonut() method will return a String type, and the donuts() method should be an Immutable Sequence.


"Examples of type assertions" should "be valid" in {
val donutStore = new DonutStore()
donutStore shouldBe a [DonutStore]
donutStore.favouriteDonut() shouldBe a [String]
donutStore.donuts() shouldBe a [Seq[_]]
}

Similar to our previous examples, the DonutStore class is as follows:


class DonutStore {
  def favouriteDonut(): String = "vanilla donut"

  def donuts(): Seq[String] = Seq("vanilla donut", "plain donut", "glazed donut")
}

To run the Tutorial_06_Type_Test test class in IntelliJ, right click on the class name and select the Run menu item.

 

Exception Test

Throwing exceptions is generally a bad idea in programming, and even more so in Functional Programming. Exceptions break the flow of our program, and can lead to unexpected behaviour.

 

Nonetheless, as per our Scala Programming Introduction tutorial, we've seen that Scala is both an Object Oriented and Functional Programming language. For that reason, it is very likely that in a real-life Scala application (especially within a large enterprise codebase), you may be interfacing with some Object Oriented pattern or with a legacy Java library, which may be throwing exceptions.

 

As a result, we'll show how you can use ScalaTest to write tests versus known exceptions. Let's go ahead and modify our DonutStore class with a dummy printName() method, which basically throws an IllegalStateException.


class DonutStore {
  def favouriteDonut(): String = "vanilla donut"

  def donuts(): Seq[String] = Seq("vanilla donut", "plain donut", "glazed donut")

  def printName(): Unit = {
    throw new IllegalStateException("Some Error")
  }
}

To catch the exception thrown by printName() method from the DonutStore class, you can use ScalaTest's intercept method:


  "Method DonutStore.printName()" should "throw IllegalStateException" in {
    val donutStore = new DonutStore()
    intercept[java.lang.IllegalStateException] {
      donutStore.printName()
    }
  }

If you need to verify the exception and its message, you can use a combination of ScalaTest's the() and thrownBy() methods:


  "Exception thrown by method printName()" should "contain message Some Error" in {
    val donutStore = new DonutStore()
    val exception = the [java.lang.IllegalStateException] thrownBy {
      donutStore.printName()
    }
    // here we verify that the exception class and the internal message
    exception.getClass shouldEqual classOf[java.lang.IllegalStateException]
    exception.getMessage should include ("Some Error")
  }

In case you only need to test the exception message, you can use ScalaTest's the()thrownBy() and should have message methods:


  "Exception thrown by method printName()" should "contain message Some Error using ScalaTest should have message methods" in {
    val donutStore = new DonutStore()
    the [java.lang.IllegalStateException] thrownBy {
      donutStore.printName()
    } should have message "Some Error"
  }

To write a test to verify only the type of the Exception being thrown, you can make use of ScalaTest an and should be thrownBy() methods:


    an [java.lang.IllegalStateException] should be thrownBy {
      new DonutStore().printName()
    }

Right click on the class Tutorial_07_Exception_Test and select the Run menu item to run the test within IntelliJ.

 

Private Method Test

If you are following a Functional Programming approach, it would be perhaps rare to test private methods. Instead, you would achieve similar behaviour by making use of say Partial Function, Partially Applied Functions or Higher Order Functions - to name a few.

 

However, as we've noted in the previous ScalaTest Exception Test tutorial, in a large enterprise code base, you will most certainly have to interface with legacy or Object Oriented libraries. In turn, these may require you to make use of testing private methods in classes. With ScalaTest, you also have the ability to easily test private methods by making use of import org.scalatest.PrivateMethodTester._

 

Let's begin by adding two methods to our DonutStore class: a donutPrice() method which will return a price for a given donut, and a private discountByDonut() method which applies a certain discount for a given donut. We are keeping both methods fairly simple in order to focus on the testing of private method using ScalaTest. Having said that, it is worth noting that the methods below do have code smell by having internal state and side effects!


def donutPrice(donut: String): Option[Double] = {
    val prices = Map(
      "vanilla donut" -> 2.0,
      "plain donut"   -> 1.0,
      "glazed donut"  -> 3.0
    )
    val priceOfDonut = prices.get(donut)
    priceOfDonut.map{ price => price * (1 - discountByDonut(donut)) }
  }

  private def discountByDonut(donut: String): Double = {
    val discounts = Map(
      "vanilla donut" -> 0.2,
      "plain donut"   -> 0.1,
      "glazed donut"  -> 0.3
    )
    discounts.getOrElse(donut, 0)
  }

As shown below, by simply importing org.scalatest.PrivateMethodTest._, you get access to an easy syntax for testing private methods using ScalaTest. In our example, we're testing the private method discountByDonut() for the input of vanilla donut.


  "Example of testing private method" should "be valid" in {
    val donutStore = new DonutStore()
    val priceWithDiscount = donutStore.donutPrice("vanilla donut")
    priceWithDiscount shouldEqual Some(1.6)

    // test the private method discountByDonut()
    import org.scalatest.PrivateMethodTester._
    val discountByDonutMethod = PrivateMethod[Double]('discountByDonut)
    val vanillaDonutDiscount = donutStore invokePrivate discountByDonutMethod("vanilla donut")
    vanillaDonutDiscount shouldEqual 0.2
  }

To run the test code in IntelliJ, you can right click on the Tutorial_08_Private_Method_Test class and select the Run menu item.

 

Future Method Test

In Chapter 9 on Futures Tutorials, we showed how you can create asynchronous non-blocking operations by making use of Scala Futures. But, what about testing asynchronous methods? Thanks to ScalaTest, that's pretty easy by importing the org.scalatest.concurrent.ScalaFutures trait.

 

Let's go ahead and add an asynchronous method named donutSalesTax(), which returns a future of type Double. The actual implementation of this method is redundant, as we're simply using a Thread.sleep(3000) to simulate a somewhat long-running operation. Instead, we'll focus on how to use ScalaTest to test this non-blocking method.

 

To this end, you will need to first import the org.scalatest.concurrent.ScalaFutures trait, along with extending the usual FlatSpec class and importing the Matchers trait.

 

Next, you can provide your own PatienceConfig to determine the duration of the future operation. Finally, to test the future donutSalesTax() method, you can use the whenReady() method and pass-through the donutSalesTax() method as shown below.


class Tutorial_09_Future_Test extends FlatSpec with Matchers with ScalaFutures {

  implicit override val patienceConfig: PatienceConfig =
    PatienceConfig(timeout = Span(5, Seconds), interval = Span(500, Millis))

  "Example of testing asychronous futures" should "be valid" in {
    val donutStore = new DonutStore()
    val donutSalesTaxFuture = donutStore.donutSalesTax("vanilla donut")

    whenReady(donutSalesTaxFuture) { salesTaxForVanillaDonut  =>
      salesTaxForVanillaDonut shouldEqual 0.15
    }
  }

}

In IntelliJ, right click on the Tutorial_09_Future_Test class and select the Run menu item to run the test code.

 

Convert Java collection to Scala collection


 // Step 1: Import converters
 import scala.collection.JavaConverters._

 // Step 2: Assume you have a Java Map
 val donutJavaMap: java.util.Map[String, Double] = new java.util.HashMap[String, Double]()
 donutJavaMap.put("Plain Donut", 2.50)
 donutJavaMap.put("Vanilla Donut", 3.50)

 // Step 3: Convert the Java Map by calling .asScala
 val donutScalaMap = donutJavaMap.asScala

 // Step 4: You now have a Scala Map
 val pricePlainDonut = donutScalaMap("Plain Donut")
 val setDonuts = donutScalaMap.map(_._1).toSet

 

Add line break or separator for given platform


 /** Add line break or separator for given platform **/
 val lineBreak = scala.compat.Platform.EOL
 println(s"First line $lineBreak second line")

 

Convert multi-line string into single line


  /** Convert multi-line string to single line **/
 // Step 1: Define an implicit class to strip out line endings
 implicit class StringConversion(str: String) {

 def inline(): String = str.replaceAll(scala.compat.Platform.EOL," ")

 }

 // Step 2: Create a multi-line string
 val multilineStr =
 """
 |Plain Donut
 |Vanilla Donut
 """.stripMargin


 println(s"Multi-line as single line = ${multilineStr.inline()}")

 

Check the value of an Option


/** Check the value of an Option **/
 Some(5).contains(5)

 

Cannot find an implicit ExecutionContext


 /** Cannot find an implicit ExecutionContext **/
 // Step 1: Need to import scala.concurrent.ExecutionContext.Implicits.global
 import scala.concurrent.ExecutionContext.Implicits.global

 val future: Future[Int] = Future {
   // some long running operation
   1
 }

 

Read a file and return its contents as a String


  /** Function to read a file and return a String of its contents **/
  def readFile(file: String): String = {
    Source
      .fromInputStream(getClass.getResourceAsStream(file))
      .getLines
      .mkString("\n")
  }

 

Create enum using sealed trait


  /** Create enum using sealed trait **/
  sealed trait Donut
  case object Vanilla extends Donut
  case object Chocolate extends Donut
  case object Plain extends Donut

  def isValidDonut(donut: Donut) = {
    donut match {
      case Vanilla | Chocolate | Plain => println("Valid donut")
      case _ => println("Unknown donut!")
    }
  }

 

Int division in Scala and return a float which keeps the decimal part


  /** Int division in Scala and return a float which keeps the decimal values: **/
  val donutQuantity: Int = 10
  val donutTotalCost: Int = 25
  val donutPrice = donutTotalCost.toFloat / donutQuantity
  println(s"Cost of one donut = $donutPrice")

NOTE: You have to be explicit and call .toFloat

Nadim Bahadoor on FacebookNadim Bahadoor on GithubNadim Bahadoor on LinkedinNadim Bahadoor on Twitter
Nadim Bahadoor
Technology and Finance Consultant with over 14 years of hands-on experience building large scale systems in the Financial (Electronic Trading Platforms), Risk, Insurance and Life Science sectors. I am self-driven and passionate about Finance, Distributed Systems, Functional Programming, Big Data, Semantic Data (Graph) and Machine Learning.
Other allaboutscala.com tutorials you may like: