Jules Ivanic
Jules Ivanic

Reputation: 1617

Play 2.4 Scaldi WS tests

I want to test a WS client with a fake server like it's explained in the Play 2.4 documentation here : https://www.playframework.com/documentation/2.4.x/ScalaTestingWebServiceClients

But I'm doing DI with Scaldi and i'm not able to adapt the Play's documentation code to use Scaldi.

Can someone help me ?

The code to adapt is mostly this (come from the Play doc) :

"GitHubClient" should {
  "get all repositories" in {

    Server.withRouter() {
      case GET(p"/repositories") => Action {
        Results.Ok(Json.arr(Json.obj("full_name" -> "octocat/Hello-World")))
      }
    } { implicit port =>
      WsTestClient.withClient { client =>
        val result = Await.result(
          new GitHubClient(client, "").repositories(), 10.seconds)
        result must_== Seq("octocat/Hello-World")
      }
    }
  }
}

Upvotes: 1

Views: 325

Answers (2)

dberry
dberry

Reputation: 106

Jules,

Late response, but I just went through this myself. Here is how I test with ScalaTest(Play Spec), a test server, and WSTestClient using wsUrl. This is for play 2.5.4. The project is here: reactive-rest-mongo

class UsersSpec extends PlaySpec with Injectable with OneServerPerSuite {

  implicit override lazy val app = new ScaldiApplicationBuilder()
    .build()

  "User APIs" must {

    "not find a user that has not been created" in {
      val response = Await.result(wsUrl("/users/1").get, Duration.Inf)
      response.status mustBe NOT_FOUND
      response.header(CONTENT_TYPE) mustBe None
      response.bodyAsBytes.length mustBe 0
    }
  }
}

Upvotes: 2

tenshi
tenshi

Reputation: 26566

An example of general approach for integration testing can be found here:

https://github.com/scaldi/scaldi-play-example/blob/master/test/IntegrationSpec.scala#L22

It's not direct equivalent though, since it uses HttpUnit instead of WSClient. More precise equivalent would be something like this:

import scaldi.play.ScaldiApplicationBuilder._
import scaldi.Injectable._

val fakeRotes = FakeRouterModule {
  case ("GET", "/repositories") => Action {
    Results.Ok(Json.arr(Json.obj("full_name" -> "octocat/Hello-World")))
  }
}

withScaldiInj(modules = fakeRotes :: Nil) { implicit inj ⇒
  val client = inject [WSClient]

  withTestServer(inject [Application]) { port ⇒
    val result = Await.result(
      new GitHubClient(client, s"http://localhost:$port").repositories(), 10.seconds)

    result must_== Seq("octocat/Hello-World")
  }
}

It uses a WSClient, just like in your example. The difference is that Application and WSClient are injected and test does not rely on a global state or factories.

In order to use this example you also need this small helper function which creates a test server based on the injected Application:

def withTestServer[T](application: Application, config: ServerConfig = ServerConfig(port = Some(0), mode = Mode.Test))(block: Port => T)(implicit provider: ServerProvider): T = {
  val server = provider.createServer(config, application)

  try {
    block(new Port((server.httpPort orElse server.httpsPort).get))
  } finally {
    server.stop()
  }
}

Play already provides some helper functions out-of-the-box to create a test server, but most of them either reinitialize an application of rely on Guice. That's because you need to create your own simplified version of it. This function is probably a good candidate for inclusion in scaldi-play.

Upvotes: 3

Related Questions