-
Book Overview & Buying
-
Table Of Contents
Scala Test-Driven Development
By :
Once we have both Scala and SBT set up, it is time to revisit our understanding of TDD. What better way to summarize than to write a very mundane "Hello World" Scala application using TDD. Let us take this application requirement as a user story.
Story definition
As a user of the application
Given that I have a publically accessible no argument function named
displaySalutation
When the function is invoked
Then a string with the value Hello World is returned.
Notice the language of the story. This is called the Give-When-Then notation, which is used to specify the behavior of the system. Dan North and Chris Matte, as part of (Behavior-Driven Development (BDD), developed this language. We will discuss this parlance in more detail when we look at BDD.
Run these commands on the command line to create the directory structure:
mkdir helloworldcd helloworldmkdir -p src/main/scalamkdir -p src/test/scalamkdir –p projectCreate a file using any editor with the content given underneath and save it as build.sbt:
name := "HelloWorld"
version := "1.0"
scalaVersion := "2.11.8"
libraryDependencies += "org.scalatest" %% "scalatest" % "2.2.6" % "test"
Use the version of Scala that you got installed locally.
How easy would it have been to write just a Scala function that will return Hello World? Then again, where is the fun in that? Since we have made a commitment to learn TDD, let's start with the test:
com.packt package under the src/test/scala folder.HelloTest.scala: package com.packt
import org.scalatest.FunSuite
class HelloTests extends FunSuite {
test("displaySalutation returns 'Hello World'") {
assert(Hello.displaySalutation == "Hello World")
}
}
sbt test from under the project root directory :/Packt/.$ sbt test [info] Loading project definition from /helloworld/project [info] Set current project to Chap1 (in build file:/Packt/ helloworld /) [info] Compiling 1 Scala source to /Packt/ helloworld /target/scala/classes... [info] Compiling 1 Scala source to /Packt/ helloworld /target/scala/test- classes... [error] /Packt/ helloworld /src/test/scala/com/packt/ HelloTest.scala:7: not found: value Hello [error] assert(Hello.displaySalutation == "Hello World") [error] ^ [error] one error found [error] (test:compileIncremental) Compilation failed
Hey presto! An error. Well that's what we had expected. Congratulations! This is your first failing test. Now let's fix the test one step at a time.
Looking at the compilation error, we can see that the compiler could not find the Hello.scala class. Let's create a new package com.packt under src/main/scala. Add a class Hello.scala here with this content:
package com.packt
object Hello {
}
You may be wondering why we are adding an empty class here. This is because we are doing TDD and just doing enough to make the first error go away. Now we will re-run sbt test and see output similar to this:
[info] Loading project definition from /Packt/HelloWorld/project [info] Set current project to Chap1 (in build file:/Packt/HelloWorld/) [info] Compiling 1 Scala source to /Packt/HelloWorld/target/ scala/classes... [info] Compiling 1 Scala source to /Packt/HelloWorld/target/scala/test- classes... [error] /Packt/Chap1/src/test/scala-2.11/com/packt/HelloTest.scala:7: value displaySalutation is not a member of object com.packt.Hello [error] assert(Hello.displaySalutation == "Hello World") [error] ^ [error] one error found [error] (test:compileIncremental) Compilation failed
Again we get an error, but this time it is complaining about a missing member, displaySalutation. At this point, we can make changes to the class Hello and introduce a member function, displaySalutation. It will look like this:
package com.packt
object Hello {
def displaySalutation = ""
}
Now re-run sbt test. This time the output should look similar to this:
$ sbt test [info] Loading project definition from /Packt/HelloWorld/project [info] Set current project to Chap1 (in build file:/Packt/ HelloWorld /) [info] Compiling 1 Scala source to /Packt/ HelloWorld /target/scala/classes... [info] HelloTests: [info] - displaySalutation returns 'Hello World' *** FAILED *** [info] "[]" did not equal "[Hello World]" (HelloTest.scala:7) [info] Run completed in 227 milliseconds. [info] Total number of tests run: 1 [info] Suites: completed 1, aborted 0 [info] Tests: succeeded 0, failed 1, canceled 0, ignored 0, pending 0 [info] *** 1 TEST FAILED *** [error] Failed tests: [error] com.packt.HelloTests [error] (test:test) sbt.TestsFailedException: Tests unsuccessful
The output is better this time as there are no compilation problems. The build fails because of the failure of the test. Our test makes an assertion that the output of displaySalutation should be Hello World, and our current implementation of Hello.scala (deliberately) returns an empty string. At this point, we can change the empty string to "Hello World" so the content of Hello.scala looks like this:
package com.packt
object Hello {
def displaySalutation = "Hello World"
}
Let us re-run the task sbt test. This time we will get the expected output:
$ sbt test [info] Loading project definition from /Packt/HelloWorld/project [info] Updating {file:/Packt/HelloWorld/project/}helloworld-build... [info] Resolving org.fusesource.jansi#jansi;1.4 ... [info] Done updating. [info] Set current project to HelloWorld (in build file:/Packt/HelloWorld/) [info] Updating {file:/Packt/HelloWorld/}helloworld... [info] Resolving jline#jline;2.12.1 ... [info] Done updating. [info] Compiling 1 Scala source to /Packt/HelloWorld/target/scala/classes... [info] Compiling 1 Scala source to /Packt/HelloWorld/target/scala/test- classes... [info] HelloTests: [info] - the name is set correctly in constructor [info] Run completed in 327 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.
This leads us to a solution that is fully test-driven. We can argue about the notion of too much testing and the triviality of the tests, but let's hold off till later chapters. For now, just bask in the glory of having written your first Scala TDD application.
Change the font size
Change margin width
Change background colour