null
null

Reputation: 9144

ExceptionHandler doesn't work with spray test-kit?

I'm trying Spray's ExceptionHandler using an example in this guide: http://spray.io/documentation/1.2.2/spray-routing/key-concepts/exception-handling/

class MyServiceActor extends Actor with MyService  {

  def actorRefFactory = context

  def receive = runRoute(handleExceptions(myExceptionHandler)(myRoute))

  implicit def myExceptionHandler(implicit log: LoggingContext) =
    ExceptionHandler {
      case e: ArithmeticException =>
        requestUri { uri =>
          complete(InternalServerError, "Bad numbers, bad result!!!")
        }
    }
}

I intentionally throw ArithmeticException in the route like this:

trait MyService extends HttpService {

  val myRoute =
    path("") {
      get {
        complete {
          throw new ArithmeticException("Oops, I failed!")
          "Hello World"
        }
      }
    }
}

If I made a request with curl, it returns the error message Bad numbers, bad result!!! correctly. However when testing with Specs2 + spray testkit, it never returns the correct error message, instead it returns default 500 code error message There was an internal server error. Even using sealRoute doesn't help.

"Test" in {
  Get() ~> sealRoute(myRoute) ~> check {
    println(responseAs[String]) // Always print `There was an internal server error.`
    ok
  }
}

And on the console, I would see error trace:

[ERROR] [07/07/2016 00:31:24.661] [specs2.DefaultExecutionStrategy-1] [ActorSystem(com-example-MyServiceSpec)] Error during processing of request HttpRequest(GET,http://example.com/,List(),Empty,HTTP/1.1)
java.lang.ArithmeticException: Oops, I failed!
        at com.example.MyService$$anonfun$1.apply(MyService.scala:62)
        at com.example.MyService$$anonfun$1.apply(MyService.scala:61)
        at spray.routing.directives.RouteDirectives$$anonfun$complete$1$$anon$3.apply(RouteDirectives.scala:49)
        at spray.routing.directives.RouteDirectives$$anonfun$complete$1$$anon$3.apply(RouteDirectives.scala:48)
        at spray.routing.directives.BasicDirectives$$anonfun$mapRequestContext$1$$anonfun$apply$1.apply(BasicDirectives.scala:30)
        ...

I put a println command in the myExceptionHandler and found out the myExceptionHandler never get executed.

Anyone know why it doesn't work and the solution?

Upvotes: 2

Views: 214

Answers (1)

stholzm
stholzm

Reputation: 3455

Apparently sealRoute is not enough, because the exception handler is resolved implicitly, as described here: http://spray.io/documentation/1.2.4/spray-testkit/

In your case, MyServiceActor has an exception handler, but in the test case you use MyService/myRoute directly, so the exception handler is not picked up.

This documentation page was useful: http://spray.io/documentation/1.2.4/spray-routing/key-concepts/exception-handling/

The solution is to bring an implicit ExceptionHandler into scope in the test case. So in this example:

"Test" in {
  implicit val testExceptionHandler = ExceptionHandler {
    case e: ArithmeticException =>
      requestUri { uri =>
        complete(InternalServerError, "Bad numbers, bad result!!!")
      }
  }
  Get() ~> sealRoute(myRoute) ~> check {
    println(responseAs[String])
    ok
  }
}

It worked, but of course the duplication is not super elegant. Maybe you can access the exception handler from MyServiceActor in your test and reuse production code. I just put testExceptionHandler into a base class all tests inherit from.

Upvotes: 0

Related Questions