Hello,
I am just getting started with Scalatest and ScalaMock, and as a first attempt I am writing a simple test that ensures that a get() method returns a proper result. The get() method takes a String and returns an instance of SFConfig (a user-defined Salesforce configuration value).
Because my application is built with the Play! framework, my application code ordinarily depends on a "Play" singleton object, which represents an application. Play has a current() method, which gets the currently running application, then on that current application instance calls a configuration() method, which retrieves a Configuration instance that represents the current application's configuration values.
I do not want my unit test to depend on a running application, nor on the configuration values which I store in Play's application.conf file, but on a fake configuration, which I would like to mock with ScalaMock. My approach, as you can see below, is to mock the Play object and the chain of dependencies which are invoked by the subject under test. (Thus, the configuration, the config values, the current application, etc. are all mocked.)
Here is the code for my suite:
class MySuite extends FlatSpec with MockFactory {
val legitimateConfigKey = "My.credentials"
/** First, mock the configuration object to be used by a mock application */
class MockConfiguration extends Configuration(mock[Config])
val mockConfiguration = mock[MockConfiguration]
/**
* All we care about for this test is that the configuration will give us back
* a salesforce configuration value that looks like what we store in our application's
* configuration, so we mock that, too.
*/
val mockConfigValue = new java.util.HashMap[String, Object]
mockConfigValue.put("username", "testUser")
mockConfigValue.put("grant_type", "password")
mockConfigValue.put("password", "testPassword")
/**
* the mock config value will at first be boxed in a mocked ConfigObject. we don't
* care how unwrapped (which unboxes the value) is implemented, only that it gives
* us our value when we pass it a legitimate config key
*/
val mockConfigObject = mock[ConfigObject]
(mockConfigObject.unwrapped _).when().returns(mockConfigValue)
(mockConfiguration.getObject _).when(legitimateConfigKey).returns(Some(mockConfigObject))
/**
* Now then, we can mock an application, since we don't want to run an entire application
* just to get a config string...
*/
val mockApplication = mock[Application]
/** ..and, of course, we give it our mock configuration to use in the test */
(mockApplication.configuration _).expects().returning(mockConfiguration)
/** Here is the mock Play object to use in place of the real Play object */
object MockPlay {
def current = mockApplication
}
object TestConfigContext extends SFConfigServiceComponent
with SFRestResourceServiceComponent {
val config = new { val play = MockPlay } with SFConfigService with PlayConfigurationComponent
val restResource = new { val ws = WS } with SFRestResourceService with WSUrlComponent
}
"An SFConfigService's get() method" should
"return an SFConfig type" taggedAs (Slow, RequiresApplication) in {
assert(TestConfigContext.config.get("SalesForce.credentials").isInstanceOf[Map[String, String]])
}
it should "throw an InvalidArgumentException when passed an invalid key" in {
val illegalKey = "Illegal"
intercept[IllegalArgumentException] {
TestConfigContext.config.get(illegalKey}
}}
This compiles, but when I run this Suite in the Play console, I get the following Exception:
Exception in thread "Thread-15" java.io.EOFException
at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2576)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1295)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:349)
at sbt.React.react(ForkTests.scala:98)
at sbt.ForkTests$$anonfun$apply$2$Acceptor$2$.run(ForkTests.scala:66)
at java.lang.Thread.run(Thread.java:680)
The code that seems to be causing this exception is the bit where I set the expectation on my mock config object:
val mockConfigObject = mock[ConfigObject]
(mockConfigObject.unwrapped _).when().returns(mockConfigValue)
In fact, if I *only* include this code in my test suite, I get the same exception, whereas if I exclude this code (and do not use a mock config object), I do not get the exception.
ConfigObject, which I am attempting to mock, comes from the typesafe Configuration library, and the source can be viewed
here.
I am not sure if this is an error with ScalaTest, with ScalaMock, or with my own code. Any help understanding the problem would be appreciated.
Thanks,
Ben