为什么在从单元测试调用时,Scala中没有初始化隐式变量?

时间:2016-04-19 06:25:29

标签: 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运行运行-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))   java.lang.NullPointerException at   akka.http.scaladsl.server.directives.ExecutionDirectives $$ anonfun $ handleExceptions $ 1 $$ anonfun $ $适用1.适用(ExecutionDirectives.scala:33)     在   akka.http.scaladsl.server.directives.ExecutionDirectives $$ anonfun $ handleExceptions $ 1 $$ anonfun $ $适用1.适用(ExecutionDirectives.scala:29)     在   akka.http.scaladsl.testkit.RouteTest $ TildeArrow $$不久$ 1.适用(RouteTest.scala:162)     在   akka.http.scaladsl.testkit.RouteTest $ $$ TildeArrow匿名$ 1.适用(RouteTest.scala:150)

1 个答案:

答案 0 :(得分:8)

我花了一段时间才弄明白。问题是:删除extends app将使测试成功。

问题的原因是当WebServer被声明为extends App时,它会使用DelayedInit特征的App功能。因此,构造函数中的初始化代码添加到WebServer对象的构造函数中。而是在WebServer上调用main方法时调用。所以,当他参考"路线"在测试中,这些都是空的。

混合DelayedInit特征(App扩展自DelayedInit)将重写您的类或对象模板。它不会将val和var和var添加到构造函数中,而是会添加到def delayedInit(body: => Unit)挂钩(用户代码无法访问)。显然,无论何时调用main方法,都会调用此方法。

您可以通过简单地调用" main"来验证这一点。在WebServer里面测试。如果你这样做,那么测试将通过。这是因为调用main会触发初始化,从而导致创建这些对象。

一般来说,虽然正确的解决方案可能是将路由移动到其他地方,而不是将其放在基础应用程序中。