Как можно внедрить ExecutionContext в тесты Play Framework?

#scala #playframework #playframework-2.0 #guice #scalatest

#scala #playframework #playframework-2.0 #guice #scalatest

Вопрос:

Я хочу создавать тесты для своего приложения 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 с ExecutionContext.global помощью instead и got 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 в мои тесты.

Комментарии:

1. Вы могли бы повторно использовать один из specs2: etorreborre.github.io/specs2/guide/SPECS2-3.5 /…

2. Specification Вместо PlaySpec (сохранение или удаление всех других with ) он продолжает выбрасывать java.lang.RuntimeException: There is no started application . Я действительно не знаю, как создать этот тест или хорошо ли я выполняю внедрение зависимостей :/

3. Я также использовал specs2 неявный ExecutionEnvironment и попробовал неявный ExecutionContext .

4. Если вы получите сообщение об there is no started application ошибке, оно также сообщит вам, какой фрагмент кода ожидает приложение. Способ, которым вы настроили свой тест, похоже, вообще не требует какого-либо приложения, за исключением случаев, когда вы используете держатель контекста выполнения play. Или, может быть, что-то еще в вашем коде, которое мы не видим.

5. Вы правы в том, что моему тесту на самом деле не нужен ExecutionContext, потому что я издеваюсь над результатом ComputerService. ComputerService использует ComputerDAO, а ComputerDAO нуждается в ExecutionContext для выполнения операций с базой данных, поэтому я ввожу его из ComputerController, а затем неявно отправляю его в ComputerService и, наконец, в ComputerDAO. В конце это требование для ComputerController, но оно не выполняет никаких действий. Проблема заключается в том, когда я пытаюсь создать его экземпляр, даже если он не используется.

Ответ №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:

Способ, которым этот тест должен был работать, был:

  • Расширение PlaySpec с MockitoSugar помощью и BeforeAndAfterAll
  • Перезапись:

     // 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()
    }
      

И затем все тесты выполняются без генерируемого исключения.