Almost every software developer appreciates a well written unit and functional tests, but for some reason most of us don’t like writing them. Test driven development as everything has its pros and cons, but even if you’re against TDD, tests are a great way to lock outcomes of already done and working features. They could prevent developers from destroying their previous work to some extent, while creating or fixing other functionalities.
This article will focus on writing tests for a PlayFramework server application.
ScalaTest
ScalaTest is one of the most used Scala testing libraries. It offers integration with popular testing utilities like Mockito, JUnit, Selenium and with popular IDEs like IntelliJ, Eclipse, NetBeans. Its whole library is designed to be as ‘out of the way’ as possible. It allows developers to choose which style of writing test fits them most. There are 8 available code styles that are similar to most popular libraries like xUnit, Ruby’s RSpec, specs2.
Thanks to its popularity, ScalaTest has an integration library for Play – scalatestplus-play
. To use it, you just have to add its specific version to build.sbt
like this:
libraryDependencies ++= Seq(
“org.scalatestplus.play” %% “scalatestplus-play” % “x.x.x” % “test”
)
Where x.x.x stands for specific version, that’s compatible with your Play version.
For testing Play applications, it’s recommended to use the PlaySpec
style of test, which uses specs like code style.
All test classes and helper classes live inside the test
directory in the project’s main catalog.
First test spec
Let’s say that we have a Calculation
object that looks like this:
object Calculation { def add(x: Int, y: Int) = { x + y } def subtract(x: Int, y: Int) = { x - y } }
In order to test it, we need to create a new class that extends PlaySpec.
class CalculationSpec extends PlaySpec { "The add method" must { "add two numbers" in { Calculation.add(2, 2) mustBe (4) } } "The subtract method" must { "subtract two numbers" in { Calculation.subtract(2, 2) mustBe (0) } } }
The code above will test both our Calculation
methods. As you can see this style of writing test is easy to read, since we’re basically building sentences that describe how the function should work. To assert truth of given statement we use the mustBe
matcher.
Let’s add one more method to our Calculation
object.
def divide(x: Int, y: Int) = { x / y }
Now we will add more tests:
"The divide method" must { "divide given numbers" in { Calculation.divide(2, 2) mustBe (1) } } it must { "throw ArithmeticException when dividing by zero" in { assertThrows[ArithmeticException] { Calculation.divide(2, 0) } } }
First one looks familiar, but the other one is a bit different. First it uses it
which copies the previous name. Next difference is with asserting. Since dividing by 0 is impossible, our method should throw and exception when it happens. To check if it’s thrown, we use assertThrows
with the exception that we want to catch.
Mocking data
As previously mentioned ScalaTest supports data mocking and Play uses Mockito for this task. To use mocked data in our test, we need to create a test spec class that extends PlaySpec
and MockitoSugar
. To show how mocking works, the example below presents two tests. One with a mocked function – it returns a specified value, even though in it’s current state it should return some other value – and the second one without mocking. Both of this test should be passed.
class TestClassSpec extends PlaySpec with MockitoSugar { "A mocked TestClass" must { "return a mocked value" in { val mockTest = mock[TestClass] when(mockTest.someMethod).thenReturn(10) mockTest.someMethod mustBe 10 } } "A TestClass" must { "return a default value" in { val test = new TestClass test.someMethod mustBe 123 } } } class TestClass { def someMethod = 123 }