Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use GuiceOneAppPerSuite with async tests #112

Open
dpoetzsch opened this issue May 15, 2018 · 5 comments
Open

Use GuiceOneAppPerSuite with async tests #112

dpoetzsch opened this issue May 15, 2018 · 5 comments

Comments

@dpoetzsch
Copy link

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?

@dpoetzsch dpoetzsch changed the title Use GuiceOneAppPerSuite with async tests Use GuiceOneAppPerSuite with async tests May 15, 2018
@MLG-ANolan
Copy link

Looking to do the same. Any suggestions?

@marcospereira
Copy link
Member

marcospereira commented Aug 23, 2018

Hi @dpoetzsch,

Thanks for investigating this. Another solution is to declare GuiceOneAppPerSuite with a self-type for Suite instead of TestSuite (Suite is the parent type for both TestSuite and AsyncTestSuite):

trait GuiceOneAppPerSuite extends BaseOneAppPerSuite with GuiceFakeApplicationFactory {
  this: org.scalatest.Suite =>
}

That way, it should work when you mix GuiceOneAppPerSuite and AsyncTestSuite or TestSuite. If you want to give it a try and submit PR, let me know so I can help you by reviewing it. :-)

Best.

@tnielens
Copy link

tnielens commented Mar 11, 2019

For those looking for a quick hack, you can declare the async suite as a nested suite:

import org.scalatest._
import org.scalatestplus.play.guice.GuiceOneAppPerSuite

import scala.collection.immutable

class GuiceOneAppPerAsyncSuite extends TestSuite with GuiceOneAppPerSuite {

  val nestedSuite = new AsyncFlatSpec {
    // async tests here
  }

  override def nestedSuites: immutable.IndexedSeq[Suite] = Vector(nestedSuite)
}

@wuservices
Copy link

@marcospereira I'm also no Scala magician, but I was trying out your suggestion above to attempt this:

trait GuiceOneAppPerSuite extends BaseOneAppPerSuite with GuiceFakeApplicationFactory {
  this: org.scalatest.Suite =>
}

It seems like that won't work because BaseOneAppPerSuite extends TestSuiteMixin. Does this mean you're left with rewriting a bunch of the tree with async versions like @dpoetzsch's original suggestion?

kwinter added a commit to kwinter/scalatestplus-play that referenced this issue Apr 25, 2020
this allows implementing specs to use either sync or async suites
@kwinter
Copy link

kwinter commented Apr 25, 2020

took at crack at this, moved TestSuite/TestSuiteMixin to Suite/SuiteMixin: #255

kwinter added a commit to kwinter/scalatestplus-play that referenced this issue Apr 29, 2020
for app and server fixtures.  fixes playframework#111, and also doesn't start
app/server if test is excluded via tags
maiksaray added a commit to maiksaray/YALTA-backend that referenced this issue Dec 6, 2020
AsyncSpec does not work for some reason...
Here's a couple of workaround for future review playframework/scalatestplus-play#112
maiksaray added a commit to maiksaray/YALTA-common that referenced this issue Dec 6, 2020
AsyncSpec does not work for some reason...
Here's a couple of workaround for future review playframework/scalatestplus-play#112
maiksaray added a commit to maiksaray/YALTA-backend that referenced this issue Dec 7, 2020
* Implemented UserService that can be tested

* Scalatest for UserService
AsyncSpec does not work for some reason...
Here's a couple of workaround for future review playframework/scalatestplus-play#112
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants