Grails 4.1.4 集成测试无法通过数据服务更新 Domain 类,除非使用 withNewTransaction

问题描述 投票:0回答:1

我创建了一个公共 Github 存储库来复制和说明该问题:

https://github.com/SparkersData/grails414-dataservice-int-test

简介

集成测试的目的是通过调用事务服务来更新现有的 Book 对象,事务服务又调用 GORM 数据服务来更新 Book。

BookServiceIntSpec -> [ BookService -> BookDataService ]

方括号之间部分的执行应由

@Transactional
BookService

注解引入的 Transaction 来保护

我创建了 3 种不同的 Spec 方法来演示奇怪的行为。

集成测试的序言如下:

import acme.domain.Book
import grails.gorm.transactions.Rollback
import grails.testing.mixin.integration.Integration
import spock.lang.Specification
import spock.lang.Subject

@Integration
@Rollback
@Subject(BookService)
class BookServiceIntSpec extends Specification {

    BookService bookService

    Book book

    private void setup() {
        book = new Book(title: "The Hobbit")
        book.save(flush: true, failOnError: true)
    }
}

测试用例

通过在服务中使用 GORM,可以在不创建新交易的情况下更新书籍

BookService 中的生产代码:

    Book updateWithGORM(Book toUpdate) {
        toUpdate.save(flush: true, failOnError: true)
    }

这是集成测试:

    def "It is able to update a Book without creating a new transaction, by using GORM in the service."() {
        when:
        book.title = updatedTitle
        bookService.updateWithGORM(book)

        then:
        Book.findByTitle(updatedTitle) != null

        where:
        updatedTitle = "Bilbo The Hobbit"
    }

如果使用数据服务,则无法在不创建新事务的情况下更新书籍

BookService 中的生产代码

    Book updateWithDataService(Book toUpdate) {
        bookDataService.save(toUpdate)
    }

这是集成测试:

    def "It is NOT able to update a Book without creating a new transaction, if using a Data Service."() {
        when:
        book.title = updatedTitle
        bookService.updateWithDataService(book)

        then:
        Book.findByTitle(updatedTitle) == null //<1>

        where:
        updatedTitle = "Bilbo The Hobbit"
    }

<1> 请求更新后找不到更新的书籍

如果使用数据服务,它可以通过创建新事务来更新书籍

    Book updateWithDataService(Book toUpdate) {
        bookDataService.save(toUpdate)
    }

这是集成测试:

    def "It is able to update a Book by creating a new transaction, if using a Data Service."() {
        when:
        book.title = updatedTitle
        Book.withNewTransaction { //<1>
            bookService.updateWithDataService(book)
        }

        then:
        Book.findByTitle(updatedTitle) != null //<2>

        where:
        updatedTitle = "Bilbo The Hobbit"
    }

<1> 通过withNewTransaction,更新成功
<2> 请求更新后可以找到更新的书

结论

这要么是 Grails 4.1.4 集成测试运行时中的一个错误,要么是文档不清楚如何在集成测试中使用事务服务。我对行为解释的猜测:

  • 关闭事务后测试运行时不会刷新会话
  • 事务是在集成测试中创建的,不知何故,我在集成测试中的 GORM 代码无法访问相同的 hibernate 会话

还有其他人偶然发现这种行为或对此有解释吗?用

withNewTransaction
结束每个通话似乎是一场噩梦。

更新

更新 1:在服务方法中显式刷新会话

通过修改服务方法如下:

    Book updateWithDataService(Book toUpdate) {
        def res = bookDataService.save(toUpdate)
        sessionFactory.currentSession.flush()
        res
    }

测试行为正常,不必混乱创建新事务,也不会干扰 Hibernate 会话。

我仍然不明白为什么这不是默认行为!

grails grails-orm grails-domain-class
1个回答
0
投票

值得注意的是,在 grails 集成测试中的设置中添加的数据不会在测试运行之间被清除,除非您自己执行此操作,因此在第三次测试结束时,您的 book 表中将出现 3 行,设置使用不同的交易到测试交易。我认为这不会影响您这次的测试,但我怀疑这是否是您想要的。 您可以在测试中调用的单独方法中进行设置,也可以添加清理,例如......

void cleanup() {
    Book.where {}.deleteAll()
}

不是 100% 确定原因,但我认为您对 findByTitle 的调用受到缓存、切换到动态查找器 get 的影响,或者 findById 或 get 在您的数据服务上获取更新的书籍(在示例中添加了两者),例如

def "It is able to update a Book by creating a new transaction, if using a Data Service."() {
    when:
        book.title = updatedTitle
        bookService.updateWithDataService(book)
    then:
        bookDataService.get(book.id).title == updatedTitle //<2>
        Book.findById(book.id).title == updatedTitle
    where:
        updatedTitle = "Bilbo The Hobbit"
}

您在非数据服务示例中刷新,这就是我认为没问题的原因。

© www.soinside.com 2019 - 2024. All rights reserved.