ExceptionHandler не работает с спрей-тест-набором?

Я пробую ExceptionHandler от Spray, используя пример из этого руководства: 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!!!")
        }
    }
}

Я намеренно добавляю ArithmeticException в маршрут следующим образом:

trait MyService extends HttpService {

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

Если я сделал запрос с помощью curl, он правильно возвращает сообщение об ошибке Bad numbers, bad result!!!. Однако при тестировании с помощью набора тестов Specs2 + spray он никогда не возвращает правильное сообщение об ошибке, вместо этого он возвращает сообщение об ошибке с кодом 500 по умолчанию There was an internal server error. Даже использование sealRoute не помогает.

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

И на консоли я бы увидел трассировку ошибки:

[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)
        ...

Я поместил команду println в myExceptionHandler и обнаружил, что myExceptionHandler никогда не выполняется.

Кто-нибудь знает, почему это не работает и решение?


person null    schedule 06.07.2016    source источник
comment
Отличный вопрос! Спасибо, что разобрали на удобоваримом примере. Я дважды сталкивался с подобными проблемами. Этот ответ, наконец, помог мне :)   -  person stholzm    schedule 15.02.2018


Ответы (1)


Очевидно, sealRoute недостаточно, потому что обработчик исключений разрешается неявно, как описано здесь: http://spray.io/documentation/1.2.4/spray-testkit/

В вашем случае MyServiceActor имеет обработчик исключений, но в тестовом случае вы используете MyService/myRoute напрямую, поэтому обработчик исключений не подбирается.

Эта страница документации была полезна: http://spray.io/documentation/1.2.4/spray-routing/key-concepts/exception-handling/

Решение состоит в том, чтобы ввести неявный ExceptionHandler в область действия в тестовом примере. Итак, в этом примере:

"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
  }
}

Это сработало, но, конечно, дублирование не супер элегантно. Возможно, вы сможете получить доступ к обработчику исключений из MyServiceActor в своем тесте и повторно использовать производственный код. Я просто поместил testExceptionHandler в базовый класс, от которого наследуются все тесты.

person stholzm    schedule 15.02.2018