Setting expectation on mocked object causes java.io.EOFException when running tests in sbt

168 views
Skip to first unread message

Ben Wilhelm

unread,
Jun 21, 2013, 4:55:24 PM6/21/13
to scalate...@googlegroups.com
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:

  1. class MySuite extends FlatSpec with MockFactory {
  2.   val legitimateConfigKey = "My.credentials"
  3.  
  4.   /** First, mock the configuration object to be used by a mock application */
  5.   class MockConfiguration extends Configuration(mock[Config])
  6.   val mockConfiguration = mock[MockConfiguration]
  7.  
  8.   /**
  9.    * All we care about for this test is that the configuration will give us back
  10.    * a salesforce configuration value that looks like what we store in our application's
  11.    * configuration, so we mock that, too.
  12.    */
  13.   val mockConfigValue = new java.util.HashMap[String, Object]
  14.   mockConfigValue.put("username""testUser")
  15.   mockConfigValue.put("grant_type""password")
  16.   mockConfigValue.put("password""testPassword")
  17.  
  18.   /**
  19.    * the mock config value will at first be boxed in a mocked ConfigObject. we don't
  20.    * care how unwrapped (which unboxes the value) is implemented, only that it gives
  21.    * us our value when we pass it a legitimate config key
  22.    */
  23.   val mockConfigObject = mock[ConfigObject]
  24.   (mockConfigObject.unwrapped _).when().returns(mockConfigValue)
  25.   (mockConfiguration.getObject _).when(legitimateConfigKey).returns(Some(mockConfigObject))
  26.  
  27.   /**
  28.    * Now then, we can mock an application, since we don't want to run an entire application
  29.    * just to get a config string...
  30.    */
  31.   val mockApplication = mock[Application]
  32.  
  33.   /** ..and, of course, we give it our mock configuration to use in the test */
  34.   (mockApplication.configuration _).expects().returning(mockConfiguration)
  35.  
  36.   /** Here is the mock Play object to use in place of the real Play object */
  37.   object MockPlay {
  38.     def current = mockApplication
  39.   }
  40.  
  41.   object TestConfigContext extends SFConfigServiceComponent
  42.     with SFRestResourceServiceComponent {
  43.     val config = new { val play = MockPlay } with SFConfigService with PlayConfigurationComponent
  44.     val restResource = new { val ws = WS } with SFRestResourceService with WSUrlComponent
  45.   }
  46.  
  47.   "An SFConfigService's get() method" should
  48.     "return an SFConfig type" taggedAs (Slow, RequiresApplication) in {
  49.       assert(TestConfigContext.config.get("SalesForce.credentials").isInstanceOf[Map[String, String]])
  50.     }
  51.  
  52.   it should "throw an InvalidArgumentException when passed an invalid key" in {
  53.     val illegalKey = "Illegal"
  54.     intercept[IllegalArgumentException] {
  55.       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:
  1.   val mockConfigObject = mock[ConfigObject]
  2.   (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


Ben Wilhelm

unread,
Jun 21, 2013, 7:41:29 PM6/21/13
to scalate...@googlegroups.com
To simplify things a little, I tried this very simple suite with a basic mock object and ran it from the play console...

  1. class TestMockSuite extends FlatSpec with MockFactory {
  2.  
  3.   trait Foo { def foo: String = "foo" }
  4.  
  5.   val mockFoo = mock[Foo]
  6.   (mockFoo.foo _).when().returns("bar")
  7.  
  8.   "mockFoo" should
  9.     "return 'bar'" in {
  10.       assert(mockFoo.foo === "bar")
  11.     }
  12. }

...with the same result.
Reply all
Reply to author
Forward
0 new messages