【问题标题】:Grails 3.0.9: Spock integration tests' @Rollback annotation is not workingGrails 3.0.9:Spock 集成测试的 @Rollback 注释不起作用
【发布时间】:2016-02-23 02:31:19
【问题描述】:

我目前正在为我们的项目进行一些集成(或功能,我不是真正的 QA 而是后端开发人员,所以我可能会草率)我们项目的 REST 测试,我们使用的是 Grails 3.0.9, Spock Framework 1.0-Groovy-2.4 和 PostgreSQL DB 用于测试。

此外,我们有单独的数据库用于测试目的,每次测试后回滚更改仍然至关重要。我查看了 Grails testing doc 并尝试使用示例中所述的 @Rollback 注释 - 它只是不起作用,更改仍然提交给 DB。

因为它是工作项目,我不能提供一些真正的代码 sn-ps,希望你理解,虽然我的测试规范看起来就像在 Grails 文档示例中:从Specification@Integration 和 Grails' @Rollback 注解用于类级别。

import grails.transaction.Rollback
import grails.test.mixin.integration.Integration

@Integration
@Rollback
class SomeSpec extends Specification {

@Shared
RESTClient client

def setup() {
    client = new RESTClient('http://localhost:8080')
}

我已经尝试了所有方法:分别对每个方法使用@Rollback,尝试以相同的方式使用Spring的@Rollback,示例也是错误的-它不能应用于类,只能应用于方法,我'已经尝试改用@Transactional - 没有成功。

我还应该提到,我正在使用的控制器和服务被注释为 Grails 的@Transactional,尽管删除所有注释并没有改变任何东西。

我已经用谷歌搜索了一整天,但找不到任何有用的解决方案,因为这些解决方案主要用于 Grails 2,所以我相信我的问题在 SO 方面是独一无二的。其中一些解决方案建议使用 IntegrationSpec 而不是 Specification,报告​​它按预期工作,但它已为 Grails 3 删除并替换为 @Integration,所以我认为这不是我的选择。

我还找到了许多 @Transaction 解决方案,但这些解决方案也没有帮助,尽管在尝试应用这些解决方案时我做错了什么的可能性很小。

因此,目前唯一的选择是尝试使测试尽可能独立于数据,并在每个测试套件之后删除并重新创建数据库,但这是 IMO 非常糟糕的解决方案。我不相信没有人像我一样面临同样的问题,所以我希望找到一些可以接受的解决方案。当然,我很乐意提供我忘记提及的任何缺失信息。

更新:我已经尝试过提到的解决方法here - 我已经使用了事务,正如我之前描述的,它仍然没有效果,更改仍然提交,虽然我为每个测试获取这对消息,这意味着它实际上正在尝试做某事。不确定它是否会有所帮助,但它就在这里(它被编辑了一点):

INFO org.springframework.test.context.transaction.TransactionContext - Began transaction (1) for test context [DefaultTestContext@3dbe8e11 testClass = SomeSpec, testInstance = package.SomeSpec@5e2296ae, testMethod = $spock_feature_0_0@SomeSpec, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@6ec335b0 testClass = SomeSpec, locations = '{}', classes = '{class package.Application}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.IntegrationTest=true}', resourceBasePath = '', contextLoader = 'grails.boot.config.GrailsApplicationContextLoader', parent = [null]]]; transaction manager [org.grails.orm.hibernate.GrailsHibernateTransactionManager@25870a3a]; rollback [true] INFO org.springframework.test.context.transaction.TransactionContext - Rolled back transaction for test context [DefaultTestContext@3dbe8e11 testClass = SomeSpec, testInstance = package.SomeSpec@5e2296ae, testMethod = $spock_feature_0_0@SomeSpec, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@6ec335b0 testClass = SomeSpec, locations = '{}', classes = '{class package.Application}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.IntegrationTest=true}', resourceBasePath = '', contextLoader = 'grails.boot.config.GrailsApplicationContextLoader', parent = [null]]].

【问题讨论】:

  • 您是否尝试过这里的解决方法github.com/grails/grails-core/issues/616
  • @tim_yates,感谢您的回复,抱歉回复晚了,周末离线。我已经用与此解决方法相对应的一些信息更新了我的问题,太糟糕了,但它什么也没做,和以前一样:(

标签: spring grails groovy spock grails-3.0


【解决方案1】:

注释测试类
@WebIntegrationTest
@Transactional

用注释方法

@Rollback

对由

包裹的DataSource进行操作
org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
.newInstance(dataSource)

【讨论】:

  • 为大家澄清一下,就是-org.springframework.transaction.annotation.Transactional
【解决方案2】:

我遇到了同样的问题,但就我而言,我注意到我使用 @LoadDataSet 加载到数据库的所有内容都正确回滚。但是当我与外键引用的列进行任何交互时,@Rollback 只是不要删除引用,这会导致错误。我也尝试了很多@Transactional的解决方案,但还是不行。

我的解决方法是在cleanup() 之前调用DomainClassName.executeUpdate('delete from DomainClassName'),以访问我希望更改的所有域类。遗憾的是,这些测试现在可以正常工作了。

更新:

检查this 是否适合您。


澄清一下:我在我的测试类中使用@Transactional(propagation = Propagation.NESTED) 的组合解决了我的问题,然后,作为每个测试的最后一步,对我期望更改的每个域类调用DomainClassName.executeUpdate('delete from DomainClassName')

我的测试类现在是这样的:

@Integration
@Transactional(propagation = Propagation.NESTED)
@TestFor(MyService)
@LoadDataSet("PathInResources") //If needed
class MyTestSpec extends GebSpec {

  static transactional = true

  @Autowired
  SessionFactory session

  private void tearDownValues(){
    DomainClassName.executeUpdate('delete from DomainClassName') // Hibernate mapping will handle the table name for you
  }

  public void myTest() {
    //Test steps ...
    then:
    tearDownValues() //Call your tearDown method on the last step, after that and before cleanup(), auto rollback runs and you may have the same error as before
  }

请注意,如果您使用@LoadDataSet,您只需为您在测试中创建的数据调用DomainClassName.executeUpdate('delete from DomainClassName')。 Spock 将处理 @LoadDataSet 创建的所有内容的回滚。

【讨论】:

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