When learning a new language or framework one of my early questions is nowadays: What about testing? Obviously I asked that for Scala as well.
If there is anything to complain about I guess it is once more the large number of options one has.
Scala is highly compatible with Java and this includes the popular testing framework Junit. You can just write your tests using JUnit as you are used to but replacing Java classes with Scala classes
class ConnectionTest {
import org.junit.Test
import org.junit.Assert._
@Test
def connection_Equals_itself() {
val con = Connection(Corner(), Corner())
assertEquals(con, con)
assertEquals(con.hashCode, con.hashCode)
}
}
This works nice. But I promise once you get used to some Scala goodness you'll want to use it inside your tests as well. So time to look at some Scala test framework. There are two major test frameworks for Scala: Specs and ScalaTest.
ScalaTest
I picked ScalaTest because it allows for lots of different testing styles. So lots of opportunities for experimentation. The style I prefer so far is based on 'features'. Very differently from JUnit single tests aren't defined in separate methods, but all tests are placed directly inside the body of the class and thus are executed once the class is instantiated. (Judging by the API there are ways to fine tune that, but I haven't explored them yet.)
Tests are grouped in features and each test is named scenario. Since tests aren't methods but method calls you can't use the method name as the name of the test. Instead you provide a String parameter. This allows for loooong descriptive names. At least I consider this a good thing. One feature spec of a little project I am working on looks like this.
class ImageComparisonTest extends FeatureSpec {
feature("a user can compare the screenshot of a swing component with an image stored on disk") {
scenario("comparing a component to a NOT matching image") {
pending
}
scenario("comparing a component to a NOT existing image in headless mode") {
pending
}
scenario("comparing a component to a NOT existing image in withhead mode") {
pending
}
}
}
The Trait FeatureSpec makes the feature and scenario methods available. The 'pending' statements mark the test as .. well .. pending because neither the test nor the code is implemented yet. Pending tests are reported as 'Ignored'. The simplest way to make assertions in a test is to call assert or other methods of the Assertions object. But one can also mix in various traits for different styles of specifying assertions. For example ShouldMatchers provide a nice DSL allowing statements like this:
(5 * 23) should equal (115)
This stile of specifying assertions also guarantees really nice error messages in the case of a failing assertion. This test
class SomeTest extends FeatureSpec with ShouldMatchers
feature ("ShouldMatcher provide nice error messages"){
scenario ("Making a correct assertion"){
(5 * 23) should equal (115)
}
scenario ("Making a stupid assertion"){
(5 * 23) should equal (116)
}
}
}
results in this error message when executed:
[error] Test Failed: Feature: ShouldMatcher provide nice error messages Making a stupid assertion
org.scalatest.TestFailedException: 115 did not equal 116
at org.scalatest.matchers.Matchers$class.newTestFailedException(Matchers.scala:148)
In JUnit tests I sometimes have empty lines or even comments in my tests in order to visually seperate the setup the actual action I want to test and the assertion. With ScalaTest you have a much nicer way to do that: the GivenWhenThen trait. With it you don't put comments in your code, but method calls with a string parameter, which once again will end up in the output of your test:
class SomeTest extends FeatureSpec with ShouldMatchers with GivenWhenThen
feature ("ShouldMatcher provide nice error messages"){
scenario ("Making a correct assertion"){
given ("a number")
val number = 5
and ("an other number")
val otherNumber = 23
when ("multiplying one with the other")
val result = number * otherNumber
and ("the other way round")
val otherResult = otherNumber * number
then ("the results will be the same")
result should equal (otherResult)
}
}
}
While in this trivial case and with the weak syntax highlighting of my blog this might be a little distraction, it is really a nice form of in line commenting tests.
Of course you don't just write test, you want them executed as well. There are Runners for JUnit and TestNG so you can execute your ScalaTests with the testing framework you are used to. But I absolutely recommend the use of sbt to execute your tests directly. Sbt is a simple build tool. Setup is extremely easy, you start it enter the command ~test and it will run all your tests whenever you save your code. Really nice, especially since it is much faster then the scala compilers inside the IDEs I have seen so far.
This was only a tiny glimpse into the possibilities of testing with Scala(Test). I'm looking forward to explore even more.
Talks
Wan't to meet me in person to tell me how stupid I am? You can find me at the following events: