【问题标题】:How to rollback transaction in Grails integration tests on MongoDB如何在 MongoDB 上的 Grails 集成测试中回滚事务
【发布时间】:2013-04-17 02:04:01
【问题描述】:

当使用 MongoDB 作为数据源时,我如何(应该)配置 Grails 集成测试以自动回滚事务? (我使用的是 Grails 2.2.1 + mongodb 插件 1.2.0)

【问题讨论】:

    标签: mongodb grails grails-orm


    【解决方案1】:

    对于 spock 集成测试,我定义了一个 MongoIntegrationSpec,它可以控制清理测试数据。

    • dropDbOnCleanup = true // 将在每个特性方法执行后删除整个 DB。
    • dropDbOnCleanupSpec = true // 在规范完成后将删除整个数据库。
    • dropCollectionsOnCleanup = ["collectionA", "collectionB", ...] // 在每个特性方法执行后删除集合。
    • dropCollectionsOnCleanupSpec = ["collectionA", "collectionB", ...] // 在规范完成后丢弃集合。
    • dropNewCollectionsOnCleanup = true // 在每个特性方法执行后,所有新集合都被丢弃
    • dropNewCollectionsOnCleanupSpec = true // 规范完成后,所有新集合都将被丢弃

    这是源代码

    https://github.com/onetribeyoyo/mtm/tree/dev/src/test/integration/com/onetribeyoyo/util/MongoIntegrationSpec.groovy

    该项目也有几个使用示例。

    【讨论】:

      【解决方案2】:

      我认为这根本不可能,因为 MongoDB 不支持事务。您可以使用建议的 static transactional = 'mongo',但只有在您不刷新数据时才有帮助(我认为这种情况很少见)

      您可以手动清理setUp() 上的数据库。您可以删除要测试的域的集合,例如:

      MyDomain.collection.drop()
      

      并(可选)填写测试所需的所有数据。

      【讨论】:

      • 在 tearDown() 方法中使用 DomainObject.collection.drop() 有效。以前我曾尝试过 DomainObject.deleteAll() 并没有奏效。
      【解决方案3】:

      可以在integration 测试和/或service 类中使用static transactional = 'mongo'。 详情请参考MongoDB Plugin

      【讨论】:

      • "static transactional = 'mongo'" 独立集成测试没有帮助。顺便说一句,MongoDB 插件文档中没有关于集成测试的信息。
      • 您是否也尝试过在tearDown() 中使用disconnect()
      • 没有。你?我应该使用哪个类/对象来调用 disconnect()?它与交易有何关系?
      • 我的意思是集成测试中的tearDown() 方法。查看单元测试页面中提到的示例,该示例使用DatastoreUnitTestMixin 用于 Grails 1.3.x。早期版本的 grails 单元测试用于extend GroovyTestCase。在较新的版本中更严格。另一方面,Int 测试扩展了GroovyTestCase。查看示例中的tearDown() 方法。尝试在您的集成测试中实现相同的功能。很抱歉,我现在无法立即尝试测试它,但一旦我访问我的机器就会这样做。 :)
      • 还有几点需要注意: 1. 服务类是transactional,所以你的事务逻辑应该在grails service 层。 2.查看插件文档的交易页面。 3. 将Exception 从 grails service 类中扔回被调用方“回滚”transactions
      【解决方案4】:

      MongoDB 不支持事务!因此你不能使用它。您拥有的选项是

      1。四处走走,删除您使用的 DomainClasses 的集合。

      MyDomain.collection.drop() //If you use mongoDB plugin alone without hibernate
      MyDomain.mongo.collection.drop() //If you use mongoDB plugin with hibernate
      

      退一步是您必须为您使用的每个域都这样做

      2。删除整个数据库(您不需要显式创建它,但可以)

      String host = grailsApplication.config.grails.mongo.host
      Integer port = grailsApplication.config.grails.mongo.port
      Integer databaseName = grailsApplication.config.grails.mongo.databaseName
      
      def mongo = new GMongo(host, port)
      mongo.getDB(databaseName).dropDatabase() //this takes 0.3-0.5 seconds in my machin
      

      第二个选项更简单、更快捷。要使这项工作适用于您的所有测试,请扩展 IntegrationSpec 并添加代码以将数据库删除到清理块中(我假设您正在使用 Spock 测试框架)或为 JUnit 做类似的测试!

      希望这会有所帮助!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-07
        • 2011-07-07
        相关资源
        最近更新 更多