Play2 Framework / Scala / Specs2 - Do different FakeApplications objects separate Singleton objects?

I am new to Play2 and Scala. I am writing a simple application that uses the ReactiveMongo plugin.

I wrote a simple object to use as a DAO

object UserDAO {
  def db: reactivemongo.api.DB = ReactiveMongoPlugin.db
  def collection: JSONCollection = db.collection[JSONCollection]("users")

  collection.indexesManager.ensure(Index(List("name" -> IndexType.Ascending),
    unique = true))

  def insert(User): Future[LastError] = {
    collection.insert(unit)
  }

  def findOne(query: JsObject): Future[Option[User]] = {
    collection.find(query).one[User]
  }

  def removeOne(query: JsObject): Future[LastError] = {
    collection.remove(query, firstMatchOnly = true)
  }

  ...
}

      

Note that I am creating an index to ensure that no two users with the same name can be created. This way I can use DAO in my controllers by following

class Users extends Controller with MongoController {
  def createUser = Action.async(parse.json) {
    request =>
      request.body.validate[User].map {
        user =>
          UserDAO.insert(user).map {
            lastError =>
              Created(s"User Created")
          }
      }.getOrElse(Future.successful(BadRequest("invalid json")))
  }
}

      

So far so good. Problems come with Specs Tests. I have two test suites and I have configured them to work with different databases. The first set of tests uses the "mydb1" database:

val addConf = Map("mongodb.uri" -> ("mongodb://localhost:27017/mydb1"))

class UsersTest1 extends PlaySpecification {
  sequential

  "Users" should {
    "create a User" in new WithApplication(FakeApplication(
                             additionalConfiguration = addConf)) {
      val request = FakeRequest(POST, "/user")
        .withJsonBody(Json.obj(
          "name" -> "foo",
          "age" -> 3))

      val response = route(request)
      ...
      ...
    }
  }
}

      

The second set of tests uses the database "mydb2"

val addConf = Map("mongodb.uri" -> ("mongodb://localhost:27017/mydb2"))

class UsersTest2 extends PlaySpecification {
  sequential

  "Users" should {
    "create a User" in new WithApplication(FakeApplication(
                             additionalConfiguration = addConf)) {
      val request = FakeRequest(POST, "/user")
        .withJsonBody(Json.obj(
          "name" -> "foo",
          "age" -> 3))

      val response = route(request)
      ...
      ...
    }
  }
}

      

The problem is that after a full test run using the mongo CLI, I see that only one of the two resulting databases actually has an index present.

It looks like a Singleton UserDAO instance is shared among all FakeApplications, so the collection.indexesManager.ensure (...) function call is only executed once for all tests, when the object is accessed the first time.

As proof, I tried to move the call to collection.indexesManager.ensure (...) inside the UserDAO.insert () function, and it actually solves the problem.

I used to think of FakeApplications as completely isolated instances of an application.

+3


source to share


1 answer


At ease, yes, yes. This makes writing parallel tests very difficult (or even impossible). This will change in Play 2.4: https://www.playframework.com/documentation/2.4.x/ScalaDependencyInjection



+1


source







All Articles