Grails 3.0.9:Spock集成测试'@Rollback注解不起作用 [英] Grails 3.0.9: Spock integration tests' @Rollback annotation is not working

查看:279
本文介绍了Grails 3.0.9:Spock集成测试'@Rollback注解不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

另外,为了测试目的,我们还有单独的数据库,但在每次测试后回滚更改仍然至关重要。我浏览了 Grails测试文档,尝试使用 @Rollback 注释(如示例中所述),但它不起作用,更改仍会提交给DB。



因为它是工作项目,所以我不能提供一些真正的代码片断,希望您能理解,尽管我的测试规范看起来就像在Grails doc示例中一样:从扩展 @Integration 和Grails的 @Rollback 注解用于课程级别。

 导入grails.transaction.Rollback 
导入grails.test.mixin.integration.Integration

@Integration
@Rollback
class SomeSpec extends Specification {

@Shared
RESTClient客户端

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

我尝试了一切:分别为每种方法使用@Rollback,试图以相同的方式使用Spring的 @Rollback ,同样也有例子错误 - 它不能应用于类,只能用于方法,我尝试使用 @Transactional 代替 - 没有成功。

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



我一整天都在搜索Google,并且找不到任何有用的东西,因为这些解决方案主要针对Grails 2,所以我相信我的问题是唯一的。其中一些解决方案建议使用IntegrationSpec而不是Specification,报告​​它正在按照预期工作,但它已被移除用于Grails 3并被替换为 @Integration ,所以我认为这不是选项在我的情况。



我也发现了很多 @Transaction 解决方案,但那些解决方案也没有帮助,虽然有一个小的我尝试应用这些解决方案时遇到了错误。



因此,目前唯一的选择是尝试尽可能独立于数据进行测试,在每个测试套件后创建数据库,但这是IMO很差的解决方案。我不相信没有人像我一样面对同样的问题,所以我希望找到一些可以接受的解决方案。当然,我会很乐意提供任何我忘记提及的信息。

更新:我已经尝试了提到的解决方法这里 - 我已经使用了Transactional,就像我之前描述的那样,它仍然没有效果,变化仍然是承诺,虽然我得到这对每个测试的消息,这意味着它实际上试图做一些事情。不确定它会有帮助,但它在这里(它被编辑了一下):



INFO org.springframework.test.context.transaction .TransactionContext - 为测试上下文开始事务[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]]];事务管理器[org.grails.orm.hibernate.GrailsHibernateTransactionManager@25870a3a]; rollback [true]
INFO org.springframework.test.context.transaction.TransactionContext - 回滚事务用于测试上下文[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]]] code>

解决方案

我有同样的问题,但在我的情况下,我注意到我加载到数据库的所有内容 @LoadDataSet 被正确回滚。但是,当我与外键引用的列进行任何交互时, @rollback 只是不删除引用并导致错误。我也尝试了很多 @Transactional 解决方案,但仍然无效。



我的解决方法是调用<在 cleanup()之前的code> DomainClassName.executeUpdate('从DomainClassName中删除),到所有我希望更改的domainClasses。这些测试现在可以正常工作,但并不正确,可悲。
$ b

更新:



如果工作正常




为了澄清:我使用 @Transactional(传播= Propagation.NESTED)在我的测试类,然后,作为每个测试的最后一步,调用 DomainClassName.executeUpdate('删除DomainClassName')我的测试类现在是这样的:




pre> @Integration
@Transactional(propagation = Propagation.NESTED)
@TestFor(MyService)
@LoadDataSet(PathInResources)//如果需要
class MyTestSpec扩展GebSpec {

static transactional = true
$ b $ @Autowired
SessionFactory会话

private void te arDownValues(){
DomainClassName.executeUpdate('从DomainClassName中删除')// Hibernate映射将为您处理表名称
}

public void myTest(){
//测试步骤...
然后:
tearDownValues()//在最后一步调用tearDown方法,之后和cleanup()之前,自动回滚运行,并且您可能具有相同的错误如前
}

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


I'm currently working on some integration (or functional, I'm not really a QA but back-end dev, so I might be sloppy with terms) REST tests for our project, we are using Grails 3.0.9, Spock Framework 1.0-Groovy-2.4 and PostgreSQL DB for testing.

Also we have separate DB for testing purposes, it is still crucial that changes are rolled back after each test. I have looked through Grails testing doc and was trying to use @Rollback annotation as described in examples - and it is just not working, changes are still committed to DB.

As it is work project, I can't provide some real code snippets, hope you understand, although my test spec looks just like in the Grails doc example: extends from Specification, @Integration and Grails' @Rollback annotations are used on class level.

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

I've tried everything: used @Rollback for each method separately, tried to use Spring's @Rollback in the same way, also example was wrong about it - it can't be applied to class, only to methods, I've tried to use @Transactional instead - no success.

Also I should mention that controller and services I'm using are annotated as Grails' @Transactional, although removing all the annotations didn't change anything.

I've googled for the whole day and wasn't able to find anything useful as those solutions were mostly for Grails 2, so I believe my question is unique around SO. Some of those solutions suggested using IntegrationSpec instead of Specification, reporting it is working like intended, but it was removed for Grails 3 and replaced with @Integration, so I believe that's not an option in my case.

I've also found numerous @Transaction solutions, but those didn't help either, although there's a small chance I did something wrong while trying to apply those solutions.

So, currently the only option is to try to make test as independent of data as possible and to drop and re-create database after each test suite, but this is very poor solution IMO. I don't believe no one faced the same problem as I did, so I hope to find some acceptable solution. I'll gladly provide any missing information I forgot to mention, of course.

UPDATE: I've tried the workaround mentioned here - I've used Transactional, as I've described before, and it still has no effect, changes are still committed, although I get this pair of messages for each test, meaning it is actually trying to do something. Not sure it will be helpful, but here it goes (it is edited a bit):

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]]].

解决方案

I had the same problem, but in my case, I noticed that everything I load to database with @LoadDataSet is correctly rolled back. But when I have any interaction with a column referenced by a foreign key, @rollback just don't delete the references and this is causing the error. I also tried so many @Transactional solutions, but still doesn't work.

My workaround is to call DomainClassName.executeUpdate('delete from DomainClassName') before the cleanup(), to all domainClasses I am expecting to change. The tests now work, not properly, sadly.

Update:

Check if this works for you.


Just to clarify: I solved my problem using a combination of @Transactional(propagation = Propagation.NESTED) in my test class and then, as the last step of each test, calling DomainClassName.executeUpdate('delete from DomainClassName') to every domain class I'm expecting to change.

My test class is now something like this:

@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
  }

Note that if you use @LoadDataSet you'll only need to call DomainClassName.executeUpdate('delete from DomainClassName') for the data you create inside your test. Spock will handle the rollback for everything @LoadDataSet creates.

这篇关于Grails 3.0.9:Spock集成测试'@Rollback注解不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆