I want to set up a test in Scala that creates a mock config to provide certain values. I'm using ScalaTest 3.0.1, ScalaMock 3.4.2, and typesafe 1.3.1. The goal is to mock values for the config before running tests. The docs at http://www.scalatest.org/user_guide/testing_with_mock_objects and http://scalamock.org/user-guide/features/ seem to offer a couple options. First, here's some target code:
import com.typesafe.config.Config
class Sample(config: Config) {
private val aValue = config.getDouble("aValue")
}
It seems like it should be possible to set everything up one time, or to set up everything before each test. This attempt fails:
class SampleSpec extends FlatSpec with MockFactory with BeforeAndAfterAll {
private val mockConfig = mock[Config]
override def beforeAll {
(mockConfig.getDouble _).expects("aValue").returning(1.0).anyNumberOfTimes()
}
"testOne" should "return 1" in {
new Sample(mockConfig)
}
"testTwo" should "return 1" in {
new Sample(mockConfig)
}
}
The first test succeeds but second test in the fixture fails, and this error is produced:
Unexpected call: <mock-1> Config.getDouble(aValue)
Expected:
inAnyOrder {
}
Actual:
<mock-1> Config.getDouble(aValue)
ScalaTestFailureLocation: scala.Option at (Option.scala:120)
org.scalatest.exceptions.TestFailedException: Unexpected call: <mock-1> Config.getDouble(aValue)
Expected:
inAnyOrder {
}
Here's an alternative approach:
class SampleSpec extends FlatSpec with MockFactory with BeforeAndAfter {
private val mockConfig = mock[Config]
before {
(mockConfig.getDouble _).expects("aValue").returning(1.0)
}
"testOne" should "return 1" in {
new Sample(mockConfig)
}
"testTwo" should "return 1" in {
new Sample(mockConfig)
}
}
It produces this exception:
An exception or error caused a run to abort: assertion failed: Null expectation context - missing withExpectations?
java.lang.AssertionError: assertion failed: Null expectation context - missing withExpectations?
Why does the first attempt fail? The test specifies that getDouble
can be invoked any number of times, yet the second
test fails as if anyNumberOfTimes()
wasn't used. How should this be coded so that the method can be mocked once and
invoked repeatedly? Why does the second attempt fail? Is there a method to reset the mock so it can be reused?
I'd also like to point out the documentation page for this, with a slightly different style (using a trait):
http://scalamock.org/user-guide/sharing-scalatest/#fixture-contexts
For example:
class SampleSpec extends FlatSpec with OneInstancePerTest with MockFactory {
private val mockConfig = mock[Config]
(mockConfig.getDouble _).expects("aValue").returning(1.0).anyNumberOfTimes
"testOne" should "return 1" in {
new Sample(mockConfig)
}
"testTwo" should "return 1" in {
new Sample(mockConfig)
}
}