This is a quick introduction to setting up an asynchronous test of akka actor using TestKit and ScalaTest. With the Akka 2.6 release, Akka Typed becomes the default and the actors we’ve been using prior to the 2.6 release are now “Akka Classic.” I’ll be covering Akka Typed in some forthcoming posts. But for now, I’ll use Akka Classic to do a quick example of the basic usage of TestKit. I’m going to demo this using a really simple actor that replies to a Ping message with a Pong.
Tag: Testing
ScalaTest provides domain specific language to allow you to write behavior functions to share the same tests amongst different fixture objects. What does this mean? If you are repeating the same tests in multiple specs, you can create some very readable and compact syntax to encapsulate and reuse the tests. Create a function that encapsulates those tests. For most of the TestSuites, you use “behave like” to call that function and execute all the tests.
How you write your test code is subtly different than how you write your production code. Your tests should execute quickly, as fast tests provide fast feedback. Yet the performance of your test code isn’t as critical as your production code. Your test code should emphasize readability over uniqueness. It should minimize the amount of mental computation required for a reader to understand a test. So the bar for “DRY” test code is lower than your production code.
ScalaTest’s async test suites provide an easy and very readable way to write tests for your methods that return a Future. Using Await.ready can really clutter your tests. ScalaTest’s async test suites parallel the standard suites. For example, use AsyncFlatSpec instead of AnyFlatSpec, AsyncFeatureSpec instead of AnyFeatureSpec, etc. I’ll be using AsyncFlatSpec throughout the rest of this post.
The first thing to know about the async test suites are that each test must end in either an Assertion or a Future[Assertion].
Docker is such a powerful tool to use during development and testing. One use case I had recently was to use docker in testing a VT220 emulator that I wrote. The test cases involved running the emulator against the vttest application to validate the parsing of the escape sequences and data from an ssh server and the rendering of a screen from that server. I created a centos container with the vttest application installed and sshd, so that I could ssh into that container and run the vttest application during my tests.
Another way to keep your ScalaTest specs concise and readable is to use the OptionValues, EitherValues, and TryValues traits when testing Option, Either, or Try types. When testing options that should have a value, we could validate a value is defined and then use get to validate the value.
"An option" must "have a value" in { val some: Option[Int] = Some(1) some mustBe defined some.get mustBe 1 } Or by extending the org.
ScalaTest’s Inside trait is a great way to keep your tests very expressive, clear, and readable. For the sake of example, let’s say we have the following traits and classes to test.
object SalesData { trait Address trait Order case class CustomerAddress(streetAddress: String, city: String, stateProvince: String, postalCode: String, country: String) extends Address case class Customer(firstName: String, lastName: String) case class SalesOrder(customer: Customer, shipToAddress: Address) extends Order } A blunt force approach to writing a test which validates an address is a CustomerAddress, and then validates data in the address using only matchers might look as follows.
The withClue function in ScalaTest allows you to prepend an additional message to the test failure exception’s message. The message is only output on a test failure.
package com.dumpsterfireproject.withClue import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.must.Matchers class ExampleSpec extends AnyFlatSpec with Matchers { "Increasing a person's age" must "be done in single year increments" in { withClue("The age of") { 21 mustBe 20 } } } Produces the following output.
The age of 21 was not equal to 20 ScalaTestFailureLocation: com.
A test fixture is something used to consistently test your code. It’s the test data and/or resources used in your tests. It may be some constant data, or it may be data or resources that require some set up prior to the test and clean up/tear down after the test. Each of your tests needs to run reliably whether it’s run as part of a suite or whether it’s run alone.
“Fashion changes, but style endures.” ― Coco Chanel
ScalaTest provides great flexibility in styles of testing. If you’re just getting started using ScalaTest and are migrating from some other testing tools, ScalaTest provides some recommendations in the “Selecting testing styles” section of their user guide. But for those just getting started, which style should you choose? ScalaTest recommends as a default choice FlatSpec for unit and integration tests and FeatureSpec for acceptance tests.