玩! 2.2.4 / Akka:一起运行时测试失败,但单独确定

时间:2014-01-02 17:13:57

标签: scala testing playframework akka playframework-2.2

我有一个控制器ask在回答之前是一个演员和两个测试用例:

  • 当我运行play test时,第二次测试失败
  • 当我运行play testOnly ApplicationSpecplay testOnly IntegrationSpec时,两者都成功

我认为Akka系统在第一次测试时关闭,第二次测试没有再次启动,但为什么呢?我该如何解决这个问题呢?

控制器:

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

生成的测试非常类似于默认测试

执行两者时给出的内容:

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生成的错误页面!测试不包含我的“jumbotron”

我尝试在FakeApplication构造函数中创建新的WithBrowser,但只发生空页。

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

1 个答案:

答案 0 :(得分:12)

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

以下是解决问题的方法:

  • gamesManagerRef更改为def,使用actorFor进行查找,然后在actorOf中使用Global.onStart创建它。因此,actor在Global.onStart中创建一次,每次使用时都会完成查找。
  • 在其他对象中设置gamesManagerRef @volatile var,并使用Global.onStart方法创建actor,然后将其分配给var。通过这种方式,每次使用时都不必进行查找,但它有点难看,因为你有这种全局共享的可变状态。
  • 我首选的解决方案是编写一个插件(http://developer.vz.net/2012/03/16/writing-a-play-2-0-module/),在插件启动时查找actor ref,或者将其置于惰性val中,然后让消费者通过执行插件查找来访问actor ref

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