【问题标题】:How can ExecutionContext be injected on Play Framework tests?如何在 Play Framework 测试中注入 ExecutionContext?
【发布时间】:2017-02-21 22:43:50
【问题描述】:

我想为我的 Play Framework 应用程序创建测试,并且我继续收到 java.lang.RuntimeException: There is no started application。我有一个这样的异步控制器:

    class ComputerController @Inject()(computerService: ComputerService)(implicit executionContext: ExecutionContext){
      def add = Action.async {
        ComputerForm.form.bindFromRequest.fold(
          errorForm => Future.successful(Ok(errorForm.toString)),
          data => {
            val ip = data.ip
            val name = data.name
            val user = data.user
            val password = data.password
            val computer = Computer(ip,name,user,password)
            val futureTask = computerService.add(newComputer)
            futureTask.map(res => Redirect(routes.HomeController.home()))
          }
        )
      }
    }

注入的辅助特征:

    trait Inject {
      val injector = new GuiceApplicationBuilder()
        .in(new File("conf/application.conf").
        .in(Mode.Test)
        .injector
    }

测试是这样的:

    class ComputerControllerSpec extends PlaySpec with Inject with MockitoSugar with ScalaFutures {
      lazy val computerService = mock[ComputerService]
      when(computerService.add(any[Computer])) thenReturn Future.successful("Computer added")
      implicit lazy val executionContext = injector.instanceOf[ExecutionContext]
      val controller = new ComputerController(computerService)
      "Computer Controller" should {
        "add a new computer" in {
          val computer = ComputerFormData("127.0.0.1","Computer","user","password")
          val computerForm = ComputerForm.form.fill(computer)
          val result = controller.add.apply {
            FakeRequest()
              .withFormUrlEncodedBody(computerForm.data.toSeq: _*)
          }
          val bodyText = contentAsString(result)
          bodyText mustBe ""
        }
      }
    }

我也试过了:

  • ExecutionContext.global 初始化executionContext 隐式值,得到java.lang.RuntimeException: There is no started application

  • with OneAppPerSuite添加到ComputerControllerSpec得到:akka.actor.OneForOneStrategy - Cannot initialize ExecutionContext; AsyncExecutor already shut down

  • "add a new computer" in { 更改为"add a new computer" in new WithApplication { 并得到:java.lang.RuntimeException: There is no started application

我真的不知道如何将隐含的 ExecutionContext 注入到我的测试中。

【问题讨论】:

  • 您可以重复使用 specs2 中的那个:etorreborre.github.io/specs2/guide/SPECS2-3.5/…
  • 使用Specification 而不是PlaySpec(保留或删除所有其他withs),它会不断抛出java.lang.RuntimeException: There is no started application。我真的不知道如何创建该测试,或者我是否做得很好依赖注入:/
  • 我也使用了specs2的隐式ExecutionEnvironment,并尝试了隐式ExecutionContext
  • 如果您收到there is no started application 错误,它还会告诉您哪段代码需要应用程序。您设置测试的方式似乎根本不需要任何应用程序,除非您使用 play 的执行上下文持有者。或者可能是您的代码中我们看不到的其他内容。
  • 你说得对,我的测试不应该真的需要 ExecutionContext,因为我模拟了 ComputerService 的结果。 ComputerService 使用 ComputerDAO,而 ComputerDAO 需要 ExecutionContext 来对数据库执行操作,这就是为什么我从 ComputerController 注入它,然后隐式将其发送到 ComputerService,最后发送到 ComputerDAO。最后,它是 ComputerController 的要求,但它不执行任何操作。问题是当我尝试实例化它时,即使它没有被使用。

标签: scala playframework playframework-2.0 guice scalatest


【解决方案1】:

我猜你错过了 "new WithApplication()" 试试这个

class ComputerControllerSpec extends PlaySpec with Inject with MockitoSugar with ScalaFutures {
  lazy val computerService = mock[ComputerService]
  when(computerService.add(any[Computer])) thenReturn Future.successful("Computer added")
  implicit lazy val executionContext = injector.instanceOf[ExecutionContext]
  val controller = new ComputerController(computerService)
  "Computer Controller" should {
    "add a new computer" in new WithApplication() {
      val computer = ComputerFormData("127.0.0.1","Computer","user","password")
      val computerForm = ComputerForm.form.fill(computer)
      val result = controller.add.apply {
        FakeRequest()
          .withFormUrlEncodedBody(computerForm.data.toSeq: _*)
      }
      val bodyText = contentAsString(result)
      bodyText mustBe ""
    }
  }
}

【讨论】:

    【解决方案2】:

    这个测试的工作方式是:

    • MockitoSugarBeforeAndAfterAll 扩展PlaySpec
    • 覆盖:

      // Before all the tests, start the fake Play application
      override def beforeAll() {
        application.startPlay()
      }
      // After the tests execution, shut down the fake application
      override def afterAll() {
        application.stopPlay()
      }
      

    然后所有测试都运行,没有抛出异常。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-20
      • 2015-12-16
      • 2017-08-15
      • 1970-01-01
      • 2015-10-09
      • 2013-02-04
      • 1970-01-01
      • 2017-08-25
      相关资源
      最近更新 更多