给定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-运行-运行-WebServerSpec] [akka.actor.ActorSystemImpl(demo-WebServerSpec)]处理请求HttpRequest(HttpMethod(GET),http: //example.com/api/done-as-promised,List(),HttpEntity.Strict(无/无,ByteString()),HttpProtocol(HTTP / 1.1 ))akka.http.scaladsl上的java.lang.NullPointerException。 server.directives.ExecutionDirectives $$ anonfun $ handleExceptions $ 1 $$ anonfun $ apply $ 1.apply(ExecutionDirectives.scala:33)位于akka.http.scaladsl.server.directives.ExecutionDirectives $$ anonfun $ handleExceptions $ 1 $$ anonfun .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 .apply(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会触发初始化,从而导致创建了这些对象。
一般来说,虽然正确的解决方案可能是将路由移动到其他地方,而不是将其放置在基本应用程序内部。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句