Recently, the
presentation I submitted to Agile Brazil 2001, about writing unit tests for the JVM with Scala, was accepted and then I decided to write here some posts about/related to it in order to get more feedback before the actual presentation.
There are different libraries with that purpose in Scala, like
specsy,
specs² and
ScalaCheck, but
ScalaTest has been my favorite so far. Like you can find on their website, "ScalaTest™ is an open-source test framework for the Java Platform designed to increase your productivity by letting you write fewer lines of test code that more clearly reveal your intent". In my opinion, the best part of it is that ScalaTest is a very flexible framework, letting you use other testing frameworks, ones that you may already know, like
JUnit or
jMock, or even use
different styles of testing available on it.
Despite the name, ScalaTest doesn't aim only Scala, but also Java. Since in the end of the day Scala code becomes .class files as well, you can write tests with it for both languages. Once there are several legacy system with Java, and even more projects coming and using it, that becomes a great thing.
But before digging into ScalaTest, let's just take a quick look on Scala (I will not cover the details of the language, since there are
several other articles on the Internet that
talk about that). Check these two code fragments written in both languages:
First, a classic example: the definition of a Person class with name and age attributes. While you need more than 20 lines to write that in Java, Scala requires only one, since we don't need to write setters and getters that will be generate to us by the compiler (yes, we are not accessing the attribute with person.age, that's a generated getter). The second piece shows a small method that checks if a String contains a uppercase character. In that you can see the use of closures in Scala. It also shows that Scala syntax is a little different from Java. Those two examples are good to show the power of the Scala and how, with more features, syntax and paradigms, you can write less yet more expressive code.
Let's jump back to ScalaTest now, and the first thing you might ask is: "how I write tests with it?" The response here is kind of funny: that's up to you! Like I wrote before, ScalaTest provides several traits that you can mix together into you code, giving you or your team the option to chose the combination that feels most productive. On this post I will start with tree basic traits:
FunSuite,
ShouldMatchers and
BeforeAndAfterEach. The first is one of the most basic type of test Suite, where each test is represented by a function, similar behavior to a method annotated with JUnit's @Test. The second trait adds a DSL for tests with the should keyword (That will be more evident on the examples). The third one is very simple: it just adds methods for set up and tear down of the tests, like @Before and @After.
But first, we need some code to test. That's why we have our ultra super mega powerful TicTacToe game written in Java. Nothing very special on it. We have a couple of exceptions to address unwanted use of the game, a Enum to define he possible states of a square (X, when a X is marked; O, when a O is marked, and _ when nothing is marked on that square). The game itself with its rules go in the TicTacToe class (simple as possible):
Back to the FunSuite... as a initial step, the simplest test suite we could write is something like this:
Not many secrets on that. We created a class that extends FunSuite and uses the test keyword. Each test receives a string that describes the test ("testing hello world"), and the test block. That's the output you get when you run it on a command line:
Let's write a real test now, still keeping it simple. Once a game starts no one should have won it, right? :P
On this test, we are doing a very basic test over our game and using the simplest form of assertion, that is done through the assert keyword. However, this example doesn't show the true power of using Scala on unit tests.
Although the test looks very simple to understand, it could be even more descriptive. If you are familiar with
RSpec you have already seen the should keyword, which looks great when unit testing. What if we could do that on Scala too? The truth is that we can. Adding the ShouldMatchers trait to your test callows objects to be asserted through a should method. Let's move on now and modify a little that previous test:
We are using two matchers on it now. The first one (should not be) receives a symbol ('finished) that corresponds to a method on the object under test. ScalaTest will them will invoke that method, expecting a Boolean to be returned. But what you can see is that the test itself looks just like a normal english phrase. The second matcher (should be) used is a little simpler, just asserts that the return of ttt.winner is the same as the object inside parenthesis.
For other matchers, take a look on the trait's documentation. There are several ones for checking Strings, Ints, collections, and other basic types. If you don't like should that much, you can also use must. Just use the MustMatchers trait instead.
At my
github account, you can find the
full test suite I made for the TicTacToe game using the FunSuite. Other interesting thing you will see there is this other test:
With that, we are initially marking the square at position (0,0) and then trying to mark it again. With the should matcher, we are checking that this move is generating the expected exception. Once more you can see that the test looks just like plain english.
That's it for now. Next time I will write about the use of JUnit together with ScalaTest, since it's one of the more common test framework used Java. I hope that may help your switch to Scala, allowing you to start to write more expressive unit tests on the JVM.
Cheers.