nic*_*ojs 3 scala akka akka-http
给定Scala中的以下单例对象:
package demo
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Directives._
import akka.stream.ActorMaterializer
import scala.concurrent.Future
import scala.io.StdIn
object WebServer extends App {
  implicit val system = ActorSystem("myActorSystem")
  implicit val executionContext = system.dispatcher
  implicit val materializer = ActorMaterializer()
  val route = {
    path("api" / "done-as-promised") {
      get {
        complete {
          Future.successful("done")
        }
      }
    }
  }
  val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
}
并进行以下单元测试
package demo
import akka.http.scaladsl.testkit.ScalatestRouteTest
import org.scalactic.TypeCheckedTripleEquals
import org.scalatest.{Inspectors, Matchers, WordSpec}
class WebServerSpec extends WordSpec with Matchers with TypeCheckedTripleEquals with Inspectors with ScalatestRouteTest {
  "The WebServer /done-as-promised" should {
    "return done" in {
      // tests:
      Get("/api/done-as-promised") ~> WebServer.route ~> check {
        status.intValue() shouldEqual 200
        responseAs[String] shouldEqual "done"
      }
    }
  }
}
我收到以下错误:
[错误] [04/19/2016 07:12:18.995] [ScalaTest-run-running-WebServerSpec] [akka.actor.ActorSystemImpl(demo-WebServerSpec)]处理请求时出错HttpRequest(HttpMethod(GET),http: //example.com/api/done-as-promised,List(),HttpEntity.Strict(none/none,ByteString()),HttpProtocol(HTTP/1.1))akka.http.scaladsl中的 java.lang.NullPointerException. server.directives.ExecutionDirectives $$ anonfun $ handleExceptions $ 1 $$ anonfun $ apply $ 1.apply(ExecutionDirectives.scala:33)at akka.http.scaladsl.server.directives.ExecutionDirectives $$ anonfun $ handleExceptions $ 1 $$ anonfun $ apply $ 1 .apply(ExecutionDirectives.scala:29)at akka.http.scaladsl.testkit.RouteTest $ TildeArrow $$ anon $ 1.apply(RouteTest.scala:162)at akka.http.scaladsl.testkit.RouteTest $ TildeArrow $$ anon $ 1 .适用(RouteTest.scala:150)
我花了一段时间才弄明白.问题是:删除extends app会使测试成功.
问题的原因是当WebServer声明为时extends App,它使用特征的DelayedInit功能App.因此,构造函数中的初始化代码不会添加到WebServer对象的构造函数中.而是main在WebServer上调用方法时调用.因此,当他在测试中引用"路径"时,那些都是空的.
混合DelayedInit特征(App从中扩展DelayedInit)将重写您的类或对象模板.不是将val和var添加到构造函数中,而是将其添加到def delayedInit(body: => Unit)钩子中(用户代码无法访问).显然,无论何时调用main方法,都会调用此方法.
您可以通过在测试中的WebServer上调用"main"来验证这一点.如果你这样做,那么测试将通过.这是因为调用main会触发初始化,从而导致创建这些对象.
一般来说,虽然正确的解决方案可能是将路由移动到其他地方,而不是将其放在基础应用程序内部.