Play2 Framework / Scala / Specs2 - 不同的FakeApplications共享Singleton对象吗?

时间:2015-04-24 14:32:08

标签: scala playframework-2.0 specs2 reactivemongo

我对Play2和Scala很陌生。我正在编写一个使用ReactiveMongo插件的简单应用程序。

我写了一个简单的对象用作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)
  }

  ...
}

请注意,我创建了一个索引,以确保无法创建两个具有相同名称的用户。 通过这种方式,我可以在控制器中使用DAO,如下所示

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")))
  }
}

到目前为止一切顺利。 规格测试带来了问题。我有两个测试套件,我将它们配置为在不同的数据库上工作。 第一个测试套件使用数据库" mydb1":

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)
      ...
      ...
    }
  }
}

第二个测试套件使用数据库" 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)
      ...
      ...
    }
  }
}

问题是在完成测试运行后,使用mongo CLI我发现只有两个结果数据库中的一个实际存在索引。

看起来UserDAO单例对象实例在所有FakeApplications之间共享,因此对于所有测试,只有在第一次访问对象时,才会对collection.indexesManager.ensure(...)执行一次调用。

作为证明,我试图在UserDAO.insert()函数内部移动collection.indexesManager.ensure(...),实际上它解决了这个问题。

我曾经认为FakeApplications是完全孤立的应用程序实例。

1 个答案:

答案 0 :(得分:1)

不可思议,是的,他们这样做。这使得编写并行测试非常困难(甚至不可能)。这将在Play 2.4:https://www.playframework.com/documentation/2.4.x/ScalaDependencyInjection

中发生变化