【问题标题】:Play2 Framework/Scala/Specs2 - Do different FakeApplications share Singleton objects?Play2 Framework/Scala/Specs2 - 不同的 FakeApplications 是否共享单例对象?
【发布时间】:2015-07-03 05:13:38
【问题描述】:

我对 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(...) 的调用.

作为证明,我尝试将 collection.indexesManager.ensure(...) 调用移到 UserDAO.insert() 函数中,实际上它解决了问题。

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

【问题讨论】:

    标签: scala playframework-2.0 specs2 reactivemongo


    【解决方案1】:

    不幸的是,是的。这使得编写并行测试非常困难(甚至不可能)。这将在 Play 2.4 中发生变化:https://www.playframework.com/documentation/2.4.x/ScalaDependencyInjection

    【讨论】:

    • 或者您可以自己管理 ReactiveMongo 连接。由于 RM 提供池,因此不会影响性能。
    猜你喜欢
    • 2019-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-20
    • 1970-01-01
    相关资源
    最近更新 更多