玩 ! 2.2.4/Akka:一起运行时测试失败,但单独运行还可以 [英] Play ! 2.2.4 / Akka : tests failed when run together, but ok separately

查看:65
本文介绍了玩 ! 2.2.4/Akka:一起运行时测试失败,但单独运行还可以的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个控制器,它在回答前是ask个演员,并且有两个测试用例:

I have a controller that asks an actor before answering and two test cases:

  • 当我运行play test时,第二次测试失败
  • 当我运行play testOnly ApplicationSpecplay testOnly IntegrationSpec时,都成功
  • When I run play test the second test fails
  • When I run play testOnly ApplicationSpec and play testOnly IntegrationSpec, both succeed

我认为Akka系统在第一次测试中关闭,而在第二次测试中没有再次启动,但是为什么呢?我该如何解决呢?

I think that the Akka system is shut down by the first test and not started again by the second test, but why ? And how can I work around that ?

控制器:

object Application extends Controller {
  implicit val _ = Timeout(3 seconds)
  val gamesManagerRef = Akka.system().actorOf(GamesManager.props)

  def index = Authenticated.async { implicit request =>
    (gamesManagerRef ? GamesManager.ListWaitingGames).map {
      case GamesManager.MultipleOperationOk(games) =>
        Ok(views.html.index(GameInformation.getWaitings(request.jedis)))
    }
  }
}

单元测试:

class ApplicationSpec extends Specification {

  "Application" should {

    "send 404 on a bad request" in new WithApplication{
      route(FakeRequest(GET, "/boum")) must beNone
    }

    "render the index page" in new WithApplication{
      val home = route(FakeRequest(GET, "/")).get

      status(home) must equalTo(OK)
      contentType(home) must beSome.which(_ == "text/html")
      contentAsString(home) must contain ("jumbotron")
    }
  }
}

集成测试:

class IntegrationSpec extends Specification {
  "Application" should {
    "work from within a browser" in new WithBrowser {
      browser.goTo("http://localhost:" + port)
      browser.pageSource must contain("jumbotron")
    }
  }
}

play new

同时执行时给出的内容:

Content given when both are executed :

play.api.Application$$anon$1: Execution exception[[AskTimeoutException: Recipient[Actor[akka://application/user/$a#1274766555]] had already been terminated.]]
    at play.api.Application$class.handleError(Application.scala:293) ~[play_2.10.jar:2.2.1]
    at play.api.test.FakeApplication.handleError(Fakes.scala:203) ~[play-test_2.10.jar:2.2.1]
    at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$12$$anonfun$apply$1.applyOrElse(PlayDefaultUpstreamHandler.scala:165) ~[play_2.10.jar:2.2.1]
    at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$12$$anonfun$apply$1.applyOrElse(PlayDefaultUpstreamHandler.scala:162) ~[play_2.10.jar:2.2.1]
    at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:33) ~[scala-library.jar:na]
    at scala.util.Failure$$anonfun$recover$1.apply(Try.scala:185) ~[scala-library.jar:na]
Caused by: akka.pattern.AskTimeoutException: Recipient[Actor[akka://application/user/$a#1274766555]] had already been terminated.
    at akka.pattern.AskableActorRef$.ask$extension(AskSupport.scala:134) ~[akka-actor_2.10.jar:2.2.0]
    at akka.pattern.AskableActorRef$.$qmark$extension(AskSupport.scala:146) ~[akka-actor_2.10.jar:2.2.0]
    at controllers.Application$$anonfun$index$1.apply(Application.scala:24) ~[classes/:na]
    at controllers.Application$$anonfun$index$1.apply(Application.scala:23) ~[classes/:na]
    at controllers.Application$Authenticated$$anonfun$invokeBlock$3.apply(Application.scala:74) ~[classes/:na]
    at controllers.Application$Authenticated$$anonfun$invokeBlock$3.apply(Application.scala:69) ~[classes/:na]

是什么让Play产生错误页面!参加不包含我的超大型飞机"的测试

What gives the error page generated by Play! to the test which do not contain my "jumbotron"

我试图创建一个新的FakeApplication并提供给WithBrowser构造函数,但只会出现空白页面.

I tried to create new FakeApplication to give in the WithBrowser constructor, but only empty page happens.

可用的完整代码源: https://github.com/Isammoc/yinyang/tree/8cf8ad625b7ef35423f17503a2a35fe390352d22

推荐答案

问题是您在对象的val中持有对游戏管理器actor ref的引用.运行的第一个测试将初始化此对象,该对象将获取当前正在运行的actor系统并查找actor.然后,actor系统将关闭,并且该actor ref将变为无效.但是应用程序控制器仍然在val中保留无效的ref,因此在下一次测试运行时,它将使用关闭的actor系统中的无效的actor ref.

The problem is that you are holding a reference to games manager actor ref in a val in an object. The first test that runs will initialise this object, which will get the currently running actor system and lookup the the actor. Then the actor system will be shutdown, and that actor ref will become invalid. But the application controller still holds the invalid ref in the val, so when the next test runs, it uses the invalid actor ref from the shut down actor system.

以下是解决问题的方法:

Here are the ways you can solve it:

  • gamesManagerRef更改为def,使用actorFor查找并在Global.onStart中创建(使用actorOf).因此,actor在Global.onStart中创建一次,并且每次使用时都会进行查找.
  • 在其他某个对象中将gamesManagerRef用作@volatile var,并让您的Global.onStart方法创建actor,然后将其分配给该var.这样,不必每次使用时都进行查找,但是由于您具有此全局共享的可变状态,因此这很丑陋.
  • 我的首选解决方案是编写一个插件(
  • Change gamesManagerRef to a def, use actorFor to look it up, and create it (using actorOf) in Global.onStart. So the actor is created once in Global.onStart, and the lookup is done every time it's used.
  • Make gamesManagerRef a @volatile var in some other object, and have your Global.onStart method create the actor and then assign it to that var. In this way, the lookup doesn't have to be done each time it's used, but it's kind of ugly because you have this global shared mutable state.
  • My preferred solution is to write a plugin (http://developer.vz.net/2012/03/16/writing-a-play-2-0-module/) that looks up the actor ref when the plugin starts, or puts it in a lazy val, and then have consumers access the actor ref through doing a plugin lookup.

2018年7月23日更新:以上建议已完全过时.推荐的方法在 https://www.playframework.com/documentation/2.6中有详细记录.x/ScalaAkka .

Update 23/07/2018: The above suggestions are completely out of date. The recommended approaches are well documented in https://www.playframework.com/documentation/2.6.x/ScalaAkka.

这篇关于玩 ! 2.2.4/Akka:一起运行时测试失败,但单独运行还可以的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆