Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock a Scala singleton object?

Tags:

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?

like image 483
user2664655 Avatar asked Aug 13 '14 18:08

user2664655


People also ask

Can you mock a singleton?

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.

How can a singleton object be made executable in Scala?

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.

Is Scala object a singleton?

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.

Can we mock a trait in Scala?

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.


2 Answers

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/)

like image 107
n_l Avatar answered Sep 21 '22 10:09

n_l


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
}
like image 29
Przemek Pokrywka Avatar answered Sep 23 '22 10:09

Przemek Pokrywka