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?
Apparently
sealRouteis not enough, because the exception handler is resolved implicitly, as described here: http://spray.io/documentation/1.2.4/spray-testkit/In your case,
MyServiceActorhas an exception handler, but in the test case you useMyService/myRoutedirectly, 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
ExceptionHandlerinto scope in the test case. So in this example:It worked, but of course the duplication is not super elegant. Maybe you can access the exception handler from
MyServiceActorin your test and reuse production code. I just puttestExceptionHandlerinto a base class all tests inherit from.