ScalaTest
was introduced in
Chapter 1,
Setting up the Development Environment, but as we'll use it extensively in this lecture, we'll do a little recap here and make sure that everyone has a working
ScalaTest
environment.
In this section, we'll
have a look at a popular library for testing your Scala programs,
ScalaTest
, and see how the library uses DSLs to allow its users to write readable tests in various styles.
The purpose of looking at
ScalaTest
is twofold. First off,
ScalaTest
is a widely used testing library for Scala projects, so you're likely to end up using it when you're using Scala professionally. Secondly, it's a good example of how to use DSLs to make your code more readable.
By the end of this section, you should be able to:
ScalaTest
in your own projectsScalaTest
offers and be able to pick the one that's relevant to your projectScalaTest
tests using the F
latSpec
style
ScalaTest
is a
Scala library like any other, so you simply add it as a library dependency to your project. As we're using SBT in this book, we'll use that as an example here. Create a new SBT project with the following
build.sbt
file:
name := "Lession2-ScalaTest" scalaVersion := "2.12.4" libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.4" % "test"
For more information, refer to the installation section (http://www.scalatest.org/install) from the documentation if you want to see how to use it outside of SBT.
Create a simple test and place it in your
src/test/scala/com/example/ExampleSpec.scala
project:
package com.example import collection.mutable.Stack import org.scalatest._ class ExampleSpec extends FlatSpec with Matchers { "A Stack" should "pop values in last-in-first-out order" in { val stack = new Stack[Int] stack.push(1) stack.push(2) stack.pop() should be (2) stack.pop() should be (1) } }
To verify that your setup is correct, start an SBT session in the root of your project and run the following command:
test:compile # to compile your tests test # to run your test-suite testOnly com.example.ExampleSpec # To run just that test
You should see output similar to the following:
testOnly com.example.ExampleSpec [info] ExampleSpec: [info] A Stack [info] - should pop values in last-in-first-out order [info] Run completed in 282 milliseconds. [info] Total number of tests run: 1 [info] Suites: completed 1, aborted 0 [info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0 [info] All tests passed. [success] Total time: 6 s, completed Dec 4, 2017 9:50:04 PM
As we'll be
writing a few tests using
ScalaTest
in the following section, it's important that you have a correctly configured SBT project that you can use for the exercises. Follow these steps:
build.sbt
definition.src/test/scala/com/example/ExampleSpec.scala
with the previous contents.sbt test
command and make sure that it has detected the tests and that they pass.You've seen how to add
ScalaTest
to your Scala project and how to run the tests using SBT. You should now have a correctly configured Scala project that you can use for the remainder of the exercises in this chapter. In the next section, we'll
have a look at the various styles of tests you can write using
ScalaTest
.
ScalaTest offers a selection of different styles that you can use when you're writing your tests. What style to use depends on your team's experience and preference.
In this section, we'll have a look at some of the different styles so you can get a feeling for what style you prefer:
describe("A Set") { describe("(when empty)") { it("should have size 0") { assert(Set.empty.size == 0) } } }
FunSuite
but it focuses more on Behavior-Driven Design (BDD) by forcing you to name your tests in a manner that reads more like a specification:"An empty Set" should "have size 0" in { assert(Set.empty.size == 0) }
describe("A Set") { describe("(when empty)") { it("should have size 0") { assert(Set.empty.size == 0) } } }
"A Set" - { "(when empty)" - { "should have size 0" in { assert(Set.empty.size == 0) } } }
property("An empty Set should have size 0") { assert(Set.empty.size == 0) }
class TVSetSpec extends FeatureSpec with GivenWhenThen { info("As a TV set owner") info("I want to be able to turn the TV on and off") feature("TV power button") { scenario("User presses power button when TV is off") { Given("a TV set that is switched off") val tv = new TVSet assert(!tv.isOn) When("the power button is pressed") tv.pressPowerButton() Then("the TV should switch on") assert(tv.isOn) } } }
Example:
FunSuite
Let's have a look at the test case we created in the previous section:
package com.example import collection.mutable.Stack import org.scalatest._ class ExampleSpec extends FlatSpec with Matchers { "A Stack" should "pop values in last-in-first-out order" in { val stack = new Stack[Int] stack.push(1) stack.push(2) stack.pop() should be (2) stack.pop() should be (1) } }
There are two internal DSLs in action here. The first one is used to write your test specifications in the readable form of
"X" should "Y" in { <code> }
. This style is made available by extending
FlatSpec
. The other DSL is used to write your assertions in the form of
<expression> should be <expression>
, which is made available by extending
Matchers
.
The DSLs are implemented as a combination of classes and extension methods, but we'll look into that in greater detail when we implement our own little DSL in the next section.
The best way to get a feeling for the different styles is to use them. Select three of the styles from the previous list and convert the following test to those styles.
FunSpec
, then create a FunSpecExample.scala
file.import collection.mutable.Stack import org.scalatest._ class ExampleSpec extends FlatSpec with Matchers { "A Stack" should "pop values in last-in-first-out order" in { val stack = new Stack[Int] stack.push(1) stack.push(2) stack.pop() should be (2) stack.pop() should be (1) } }
You've seen the different styles that
ScalaTest
offers and have a rough feeling for the difference between them.
ScalaTest
is
a testing library that uses DSLs to make it possible to write very readable tests. We have seen how you can add it to your own Scala projects, we got an overview of the different styles that it supports, and we have written a few tests using different styles. In the next section, we'll look at the Scala features that Scala provides which make it possible to write DSLs in Scala.