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.
I have a confession to make. I have not been the most diligent at writing tests for my code throughout my career. Over this past year our team has committed to measuring our test coverage and have set quarterly goals for improvements in test coverage. The experience of putting such a deliberate focus on testing has been an extremely positive one. Perhaps what’s been motivating about this experience is some sort of gamification effect.
Using the database from the first in the SQL for the uninterested series, in this post we’ll cover inserts, updates and deletes. We’ll start with inserts of single rows, multiple rows, and inserts using subqueries. Then we’ll look at basic updates and performing multiple updates in a single transaction. Finally, we’ll cover deleting rows.
Inserts The basic format for inserts is:
insert into ( <list of non autogenerated columns> ) values ( <list of values to be inserted> ); Using the address table for our examples, if we could run the following