register
other register

Tuesday, July 03, 2012

Unit Test with Play Framework Sync or Async


The code below illustrate how to do response in sync mode using Play Framework.

object Deals extends Controller {
  def read(id: Long) = Action {
      Ok(readFile(new File("public/files/api/deals/deal.id.get.json"))).as("application/json").withHeaders(
      "Access-Control-Allow-Origin" -> "*",
      "Content-Type" -> "application/vnd.yell.deals.deal-v2+json,application/json; charset=utf-8")
  }
}
Unit test the controller action using scala specs2:

import org.specs2.mutable.Specification
class DealsMockSpec extends Specification {

  def jsonString = "{\"name\": \"jet\"}"
  val jsonPayload: JsValue = Json.parse(jsonString)
 
  "read action" in {
    val url = controllers.routes.Deals.read(3).url
    val result = controllers.Deals.read(3)(FakeRequest(GET, url))

    status(result) must equalTo(OK)
    header("Access-Control-Allow-Origin", result) must beSome("*")
    header("Content-Type", result).head must contain("-v")
  }
}
Using Play Framework to do async programming is really simple. Let's modify the above controller/action code with async features:

Object MyController extends Controller {

  def read(id: Long) = Action {
    val promiseOfString : Promise[String] = Akka.future { readFile(new File("public/files/api/deals/deal.id.get.json")) }
    Async {
    promiseOfString.map(content => Ok(content).as("application/json").withHeaders(
    "Access-Control-Allow-Origin" -> "*",
    "Content-Type" -> "application/vnd.yell.deals.deal-v2+json,application/json; charset=utf-8"))
    }
  }
}


Async code complains about "RuntimeException: There is no started application" when running the above unit test code. 
  
We have to tell Play! to using a TestServer so that it can handle Promise[ws.Response] which the WS.url("http://localhost:3333/deals/deal/3" will return.

"read action" in {
    running(TestServer(3333)) {
      val result : ws.Response = (WS.url("http://localhost:3333/api/deals/deal/3")).get.await(500).get
      result.status must equalTo(OK)
      result.header("Content-Type").head must contain ("-v")
      result.header("Access-Control-Allow-Origin").head must contain ("*")
    }
  }

Now run:

$play test 

It will pass. And because it is unit test, the speed is much faster than the functional test which requires the application server fully running. 

No comments: