I am building some JSON HTTP services using spray
and I am having some problems testing a RejectionHandler
. If I start the application running the command sbt run
and make the request, the RejectionHandler
process the MalformedRequestContentRejection
as expected but I am getting an IllegalArgumentException
when running the tests even with the route sealed. In the other hand, the MethodRejection
works fine. The JSON validation is done using require
The next example is based in the spray-template
repository branch on_spray-can_1.3_scala-2.11
with a POST endpoint and the new tests. I've made a fork with the entire example here
Notice the use of a case clase
for deserialize JSONs, the use of the require
method for validation and the declaration of an implicit RejectionHandler
.
package com.example
import akka.actor.Actor
import spray.routing._
import spray.http._
import StatusCodes._
import MediaTypes._
import spray.httpx.SprayJsonSupport._
class MyServiceActor extends Actor with MyService {
def actorRefFactory = context
def receive = runRoute(myRoute)
}
case class SomeReq(field: String) {
require(!field.isEmpty, "field can not be empty")
}
object SomeReq {
import spray.json.DefaultJsonProtocol._
implicit val newUserReqFormat = jsonFormat1(SomeReq.apply)
}
trait MyService extends HttpService {
implicit val myRejectionHandler = RejectionHandler {
case MethodRejection(supported) :: _ => complete(MethodNotAllowed, supported.value)
case MalformedRequestContentRejection(message, cause) :: _ => complete(BadRequest, "requirement failed: field can not be empty")
}
val myRoute =
pathEndOrSingleSlash {
post {
entity(as[SomeReq]) { req =>
{
complete(Created, req)
}
}
}
}
}
This is are the test implemented using spray-testkit
. The last one expects a BadRequest
but the test fails with an IllegarArgumentException
.
package com.example
import org.specs2.mutable.Specification
import spray.testkit.Specs2RouteTest
import spray.http._
import StatusCodes._
import spray.httpx.SprayJsonSupport._
class MyServiceSpec extends Specification with Specs2RouteTest with MyService {
def actorRefFactory = system
"MyService" should {
"leave GET requests to other paths unhandled" in {
Get("/kermit") ~> myRoute ~> check {
handled must beFalse
}
}
"return a MethodNotAllowed error for PUT requests to the root path" in {
Put() ~> sealRoute(myRoute) ~> check {
status should be(MethodNotAllowed)
responseAs[String] === "POST"
}
}
"return Created for POST requests to the root path" in {
Post("/", new SomeReq("text")) ~> myRoute ~> check {
status should be(Created)
responseAs[SomeReq] === new SomeReq("text")
}
}
/* Failed test. Throws IllegalArgumentException */
"return BadRequest for POST requests to the root path without field" in {
Post("/", new SomeReq("")) ~> sealRoute(myRoute) ~> check {
status should be(BadRequest)
responseAs[String] === "requirement failed: field can not be empty"
}
}
}
}
I am missing something?
Thanks in advance!
Your SomeReq
class is being eagerly instantiated in the Post("/", new SomeReq(""))
request builder and the require
method is invoked as soon as the class
is instantiated.
To get around this try using the following instead:
import spray.json.DefaultJsonProtocol._
Post("/", JsObject("field" → JsString(""))) ~> sealRoute(myRoute) ~> check {
status should be(BadRequest)
responseAs[String] === "requirement failed: field can not be empty"
}