After working with Scala for a while now, I thought it would be good to write down a couple of notes on my current testing setup, in particular with regards to which libraries I've settled on and which style of testing I've ended up using.
Tests end up in the same package as the code that's tested. A group of
tests are always in a class with the Tests
suffix, e.g. FooTests
.
If it's about a particular class Foo
the same applies.
scalatest
is used as the testing
framework, using
AnyWordSpec
,
that means we're using the should
/
in
pattern.
For mocking the only addition is
MockitoSugar
to make things more
Scala-ish.
How does it look like?
package com.example.foo
import org.mockito.MockitoSugar
import org.scalatest.wordspec.AnyWordSpec
class FooTests extends AnyWordSpec with MockitoSugar {
"Foo" should {
"do something" in {
val bar = mock[Bar]
val foo = new Foo(bar)
foo.baz(42L)
verify(bar).qux(42L)
}
}
}
Easy enough. There's also some more syntactic sugar for other Mockito
features, meaning
ArgumentMatchersSugar
should also be imported when
needed. Same as scalatest
has a number of additional helpers for
particular types like Option
or Either
,
e.g. OptionValues
and
EitherValues
.
class BarTests extends AnyWordSpec with Matchers with EitherValues with OptionValues {
"Bar" should {
"do something else" in {
val bar = new Bar
bar.qux(42L).left.value should be(empty)
bar.quux().value shouldBe "a value"
}
}
}
This can be done to the extreme, but usually it looks easier to me to simply assign highly nested values to a variable and continue with matchers on that variable instead.
Since sbt
is often used, the two test dependencies would look like this:
libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest" % "3.1.1" % Test,
"org.mockito" %% "mockito-scala-scalatest" % "1.13.0" % Test,
)