I'm trying out unit testing with Play framework in scala. I've written a class that checks whether the config is correct (I have a bit more error handling but I actually use this code for my test now):
class TaskQueueConfig(conf: Configuration) {
val schedulingEnabled = conf.getBoolean("schedulingEnabled").get
val processingEnabled = conf.getBoolean("processingEnabled").get
val queueName = conf.getString("queue").get
}
I'm testing this using play 2.1.1's default test setup:
class ConfigTestSpec extends Specification with Mockito with CalledMatchers {
"TaskQueueConfig" should {
"verify calls" in {
val tqConf = mock[Configuration]
tqConf.getString("queue") returns Some("queueName")
tqConf.getBoolean("schedulingEnabled") returns Some(true)
tqConf.getBoolean("processingEnabled") returns Some(true)
Logger.error("setup done")
val config = new TaskQueueConfig(tqConf)
there was one(tqConf).getString("queue")
there were two(tqConf).getBoolean(any[String])
there were one(tqConf).getBoolean("schedulingEnabled")
there were one(tqConf).getBoolean("processingEnabled")
}
}
}
I'm getting the following error:
[error] x verify calls
[error] The mock was not called as expected:
[error] configuration.getString$default$2();
[error] Wanted 1 time:
[error] -> at config.ConfigTestSpec$$anonfun$2$$anonfun$apply$4$$anonfun$apply$12.apply(ConfigTestSpec.scala:61)
[error] But was 2 times. Undesired invocation:
[error] -> at config.TaskQueueConfig.<init>(TaskQueueConfig.scala:10) (ConfigTestSpec.scala:61)
This is very strange, because the code is very isolated and there is clearly just 1 conf.getString call in TaskQueueConfig. Line 10 is the line with the getString method on it. Line 61 is the line with "there was one(tQConf).getString"
How can I fix this issue?
(there is no difference between were and was).
PS: I know this example is pretty useless to test, but I have more complex configs where there are some rules that need to be tested.
UPDATE 1
The getString method has two parameters, the second parameter has a default value of None (it's type is Option[Set[String]]). When I explicitly add the None's to the setup and verification, it still doesn't work. But when I add null
instead, I get it working.
val tqConf = mock[Configuration]
tqConf.getString("queue", null) returns Some("queueName")
tqConf.getBoolean("schedulingEnabled") returns Some(true)
tqConf.getBoolean("processingEnabled") returns Some(true)
val c = new TaskQueueConfig(tqConf)
there was one(tqConf).getString("queue", null)
there was one(tqConf).getString(any[String], any[Option[Set[String]]])
there were two(tqConf).getBoolean(any[String])
there was one(tqConf).getBoolean("schedulingEnabled")
there was one(tqConf).getBoolean("processingEnabled")
c.processingEnabled must beTrue
c.schedulingEnabled must beTrue
c.queueName must be("queueName")
So I guess the question now is, why do I have to use null?
TaskQueueConfig
match the stubbed values you set up. I know this does not answer your question, but it certainly would eliminate this issue for you... – cmbaxtergetString
. I tested the first theory myself and it does not look to me like mockito is accidentally including the stubbing in the call counts. For the scoping issue, if your real code is as it is here and the mock is not created globally, then that should also not be an issue. – cmbaxter