I am trying to mock a Scala singleton object. In particular, I need to mock the object play.api.libs.ws.WS
used inside a service component (class under test).
Using Mockito this is not possible, the test execution fails in the following way:
[error] MockitoException: :
[error] Cannot mock/spy class play.api.libs.ws.WS$
[error] Mockito cannot mock/spy following:
[error] - final classes
[error] - anonymous classes
[error] - primitive types (GeolocationSpec.scala:18)
Reading here, it seems that Scalamock allows to do it:
To mock a standalone singleton object, use
org.scalamock.annotation.mockObject
.
My service component is something like this:
trait GeolocationService {
def wsClient = WS
def getPath(origin: Location, destination: Location): Future[Route]
}
class DefaultGeolocationService extends GeolocationService {
val serviceProviderEndpoint = Play.current.configuration.getString("api.directions.endpoint")
override def getPath(origin: Location, destination: Location): Future[Route] = {
val params = Seq(
"origin" -> s"${origin.lat},${origin.lon}",
"destination" -> s"${destination.lat},${destination.lon}"
);
val resp = wsClient.url(serviceProviderEndpoint.get).withQueryString(params: _*).get()
resp.map {
// omitted code
}
}
}
My build.sbt has all these dependencies:
[...]
"org.scalatest" %% "scalatest" % "2.2.1",
"org.specs2" %% "specs2" % "2.3.13" % "test",
"org.scalamock" %% "scalamock-specs2-support" % "3.0.1" % "test",
"org.scalamock" %% "scalamock-scalatest-support" % "3.0.1" % "test",
"org.scalamock" %% "scalamock" % "3.0.1",
[...]
but I cannot find this: org.scalamock.annotation.mockObject
Probably this can be done also using EasyMock and PowerMock, but I cannot find any Scala example code.
Any idea?
There is a way to mock Singleton. Use powermock to mock static method and use Whitebox to invoke constructor YourClass mockHelper = Whitebox . invokeConstructor(YourClass. class); Whitebox.
Scala Singleton Object Singleton object is an object which is declared by using object keyword instead by class. No object is required to call methods declared inside singleton object. In scala, there is no static concept. So scala creates a singleton object to provide entry point for your program execution.
Instead of static keyword Scala has singleton object. A Singleton object is an object which defines a single object of a class. A singleton object provides an entry point to your program execution. If you do not create a singleton object in your program, then your code compile successfully but does not give output.
Scala's Traits are a powerful modeling tool, they let us implement “composition over inheritance” to achieve more flexibility in object-oriented design. However, there are some situations where mocking such composed classes in unit tests is difficult if not impossible.
Mocking singleton objects using ScalaMock 3 is not possible, however Paul Butcher expects to reintroduce this feature in ScalaMock 4 (see http://paulbutcher.com/2014/04/15/scalamock-status-report/)
Don't mock the singleton. Instead of WS, make your service component depend on a thin facade hiding it:
trait GeolocationService {
def ws: (String, Seq[String]) => Promise[Response] = { (url, params) =>
wsClient.url(serviceProviderEndpoint.get).withQueryString(params: _*).get()
}
def getPath(origin: Location, destination: Location): Future[Route]
}
and in your test, just override ws method with a mock, which is now easy to create:
val mockedWs = mock[(String, Seq[String]) => Promise[Response]]
// TODO specify mock's behavior here
val service = new DefaultGeolocationService() {
override def ws = mockedWs
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With