2016-04-19 7 views
3

die folgende Singleton Objekt in Scala Gegeben:Warum werden implizite Variablen in Scala nicht initialisiert, wenn sie vom Komponententest aus aufgerufen werden?

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) 

} 

und die folgenden Einheit Test

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

ich die folgende Fehlermeldung erhalten:

[ERROR] [04/19/2016 07:12:18.995] [ScalaTest-run-running-WebServerSpec] [akka.actor.ActorSystemImpl(demo-WebServerSpec)] Error during processing of request 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$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.apply(RouteTest.scala:150)

Antwort

8

Es dauerte eine Weile, bis Figur aus. Die Sache ist: Entfernen der extends app wird den Test erfolgreich sein.

Der Grund für das Problem ist, dass, wenn WebServer als extends App bezeichnet worden, die DelayedInit Funktionalität des App Merkmals verwendet. Aus diesem Grund ist der Initialisierungscode im Konstruktor nicht zum Konstruktor des WebServer-Objekts hinzugefügt. Stattdessen wird aufgerufen, wenn die main Methode auf dem WebServer aufgerufen wird. Wenn er also innerhalb der Tests auf die "Route" verweist, kommen alle auf Null.

Mischen in der DelayedInit Eigenschaft (App erstreckt sich von DelayedInit) wird Ihre Klasse oder Objektvorlage neu schreiben. Anstatt Ihre Werte val und var zum Konstruktor hinzuzufügen, wird sie zum def delayedInit(body: => Unit) Hook hinzugefügt (für Benutzercode nicht zugänglich). Anscheinend wird diese immer aufgerufen, wenn die Hauptmethode aufgerufen wird.

Sie können dies überprüfen, indem Sie einfach "main" auf dem WebServer innerhalb des Tests aufrufen. Wenn Sie dies tun, wird der Test bestanden. Dies liegt daran, dass der Aufruf von main die Initialisierung auslöst, was dazu führt, dass diese Objekte erstellt werden.

Im Allgemeinen ist die richtige Lösung wahrscheinlich, das Routing an einen anderen Ort zu verschieben, anstatt es in der Basis-App zu haben.

Verwandte Themen