Skip to content

Use GuiceOneAppPerSuite with async tests #112

@dpoetzsch

Description

@dpoetzsch

I have a async test suite that extends AsyncFunSpec.

Now, it seems to be not possible to also mix-in GuiceOneAppPerSuite:

// does not work
class PostSpec extends AsyncFunSpec with GuiceOneAppPerSuite with Matchers {
  it("returns posts") {
    val repo = app.injector.instanceOf[PostRepository]

    repo.create("my post").map { _ =>
      val request = FakeRequest(GET, "/posts")
      val result = route(app, request).get

      status(result) shouldEqual OK
      contentAsJson(result).as[JsArray].value.size shouldEqual 1
    }
  }
}

I am no scala magician, but I figure this is because GuiceOneAppPerSuite demands TestSuite while AsyncFunSpec inherits from AsyncTestSuite.

I figure an easy workaround would be to have an (otherwise identical) GuiceOneAppPerSuiteAsync that uses the AsyncTestSuite inheritance tree as follows:

/*
 * Copyright 2001-2016 Artima, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// this is an adjusted version of
// https://github.com/playframework/scalatestplus-play/blob/master/module/src/main/scala/org/scalatestplus/play/BaseOneAppPerSuite.scala
package org.scalatestplus.play

import org.scalatest.{Args, AsyncTestSuite, AsyncTestSuiteMixin, Status}
import org.scalatestplus.play.FakeApplicationFactory
import play.api.{Application, Play}

/**
  * The base abstract trait for one app per suite.
  */
trait BaseOneAppPerSuiteAsync extends AsyncTestSuiteMixin { this: AsyncTestSuite with FakeApplicationFactory =>

  /**
    * An implicit instance of `Application`.
    */
  implicit lazy val app: Application = fakeApplication()

  /**
    * Invokes `Play.start`, passing in the `Application` provided by `app`, and places
    * that same `Application` into the `ConfigMap` under the key `org.scalatestplus.play.app` to make it available
    * to nested suites; calls `super.run`; and lastly ensures `Play.stop` is invoked after all tests and nested suites have completed.
    *
    * @param testName an optional name of one test to run. If `None`, all relevant tests should be run.
    *                 I.e., `None` acts like a wildcard that means run all relevant tests in this `Suite`.
    * @param args the `Args` for this run
    * @return a `Status` object that indicates when all tests and nested suites started by this method have completed, and whether or not a failure occurred.
    */
  abstract override def run(testName: Option[String], args: Args): Status = {
    Play.start(app)
    try {
      val newConfigMap = args.configMap + ("org.scalatestplus.play.app" -> app)
      val newArgs = args.copy(configMap = newConfigMap)
      val status = super.run(testName, newArgs)
      status.whenCompleted { _ => Play.stop(app) }
      status
    } catch { // In case the suite aborts, ensure the app is stopped
      case ex: Throwable =>
        Play.stop(app)
        throw ex
    }
  }
}

trait GuiceOneAppPerSuiteAsync extends scala.AnyRef with BaseOneAppPerSuiteAsync with org.scalatestplus.play.guice.GuiceFakeApplicationFactory {
  this : GuiceOneAppPerSuiteAsync with org.scalatest.AsyncTestSuite =>
}

Is there an easier way? And if not, should I create a pull request to add these traits?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions