java - Grails3 单元测试不适用于多租户
问题描述
我正在尝试使用 grails 3 以及每个租户的数据库来设置应用程序,但是我遇到了应用程序本身的初始设置问题,我根本无法让单元测试正常工作。我编写了一个空服务,并在尝试通过生成的默认单元测试时收到以下错误
Could not open Hibernate Session for transaction; nested exception is java.lang.IllegalStateException: Already value [org.springframework.jdbc.datasource.ConnectionHolder@10bec8db] for key [org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy@79e57f65] bound to thread [Test worker]
org.springframework.transaction.CannotCreateTransactionException: Could not open Hibernate Session for transaction; nested exception is java.lang.IllegalStateException: Already value [org.springframework.jdbc.datasource.ConnectionHolder@10bec8db] for key [org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy@79e57f65] bound to thread [Test worker]
at org.springframework.orm.hibernate5.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:542)
at org.grails.orm.hibernate.GrailsHibernateTransactionManager.doBegin(GrailsHibernateTransactionManager.groovy:66)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:377)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:130)
at grails.gorm.transactions.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:91)
at test.TestService.serviceMethod_closure1(TestService.groovy)
at groovy.lang.Closure.call(Closure.java:418)
at groovy.lang.Closure.call(Closure.java:434)
at grails.gorm.multitenancy.Tenants.withId_closure2$_closure6(Tenants.groovy:265)
at org.grails.orm.hibernate.GrailsHibernateTemplate$1.doInHibernate(GrailsHibernateTemplate.java:153)
at org.grails.orm.hibernate.GrailsHibernateTemplate.doExecute(GrailsHibernateTemplate.java:299)
at org.grails.orm.hibernate.GrailsHibernateTemplate.execute(GrailsHibernateTemplate.java:243)
at org.grails.orm.hibernate.GrailsHibernateTemplate.executeWithNewSession(GrailsHibernateTemplate.java:150)
at org.grails.orm.hibernate.GrailsHibernateTemplate.executeWithExistingOrCreateNewSession(GrailsHibernateTemplate.java:209)
at org.grails.orm.hibernate.AbstractHibernateDatastore.withNewSession(AbstractHibernateDatastore.java:369)
at grails.gorm.multitenancy.Tenants.withId_closure2(Tenants.groovy:258)
at grails.gorm.multitenancy.Tenants$CurrentTenant.withTenant(Tenants.groovy:358)
at grails.gorm.multitenancy.Tenants.withId(Tenants.groovy:236)
at org.grails.datastore.gorm.services.DefaultTenantService.withCurrent(DefaultTenantService.groovy:71)
at test.TestServiceSpec.test something(TestServiceSpec.groovy:21)
Caused by: java.lang.IllegalStateException: Already value [org.springframework.jdbc.datasource.ConnectionHolder@10bec8db] for key [org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy@79e57f65] bound to thread [Test worker]
at org.springframework.transaction.support.TransactionSynchronizationManager.bindResource(TransactionSynchronizationManager.java:190)
at org.springframework.orm.hibernate5.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:516)
... 19 more
test.TestServiceSpec > test something FAILED
org.springframework.transaction.CannotCreateTransactionException at TestServiceSpec.groovy:21
Caused by: java.lang.IllegalStateException at TestServiceSpec.groovy:21
1 test completed, 1 failed
:test FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':test'.
根据文档,这是我的测试代码
package test
import grails.test.hibernate.HibernateSpec
import grails.testing.services.ServiceUnitTest
import org.grails.datastore.mapping.config.Settings
import org.grails.datastore.mapping.multitenancy.resolvers.SystemPropertyTenantResolver
class TestServiceSpec extends HibernateSpec implements ServiceUnitTest<TestService>{
@Override
Map getConfiguration() {
[(Settings.SETTING_MULTI_TENANT_RESOLVER_CLASS): SystemPropertyTenantResolver]
}
def setup() {
System.setProperty(SystemPropertyTenantResolver.PROPERTY_NAME, 'audi') //
}
void "test something"() {
expect:"fix me"
def a = service.serviceMethod()
true == true
}
}
和我的服务代码
package test
import grails.gorm.multitenancy.CurrentTenant
import grails.gorm.transactions.Transactional
@Transactional
@CurrentTenant
class TestService {
def serviceMethod() {
def a= " hello"
return a
}
}
最后是配置
---
#tag::grails[]
grails:
#end::grails[]
profile: web
codegen:
defaultPackage: example
spring:
transactionManagement:
proxies: false
#tag::gorm[]
gorm:
#end::gorm[]
reactor:
# Whether to translate GORM events into Reactor events
# Disabled by default for performance reasons
events: false
#tag::multiTenancy[]
multiTenancy:
mode: DATABASE
tenantResolverClass: org.grails.datastore.mapping.multitenancy.web.SessionTenantResolver
#end::multiTenancy[]
info:
app:
name: '@info.app.name@'
version: '@info.app.version@'
grailsVersion: '@info.app.grailsVersion@'
spring:
main:
banner-mode: "off"
groovy:
template:
check-template-location: false
# Spring Actuator Endpoints are Disabled by Default
endpoints:
enabled: false
jmx:
enabled: true
---
grails:
mime:
disable:
accept:
header:
userAgents:
- Gecko
- WebKit
- Presto
- Trident
types:
all: '*/*'
atom: application/atom+xml
css: text/css
csv: text/csv
form: application/x-www-form-urlencoded
html:
- text/html
- application/xhtml+xml
js: text/javascript
json:
- application/json
- text/json
multipartForm: multipart/form-data
pdf: application/pdf
rss: application/rss+xml
text: text/plain
hal:
- application/hal+json
- application/hal+xml
xml:
- text/xml
- application/xml
urlmapping:
cache:
maxsize: 1000
controllers:
defaultScope: singleton
converters:
encoding: UTF-8
views:
default:
codec: html
gsp:
encoding: UTF-8
htmlcodec: xml
codecs:
expression: html
scriptlets: html
taglib: none
staticparts: none
endpoints:
jmx:
unique-names: true
---
hibernate:
cache:
queries: false
use_second_level_cache: false
use_query_cache: false
# tag::dataSources[]
dataSource:
pooled: true
jmxExport: true
driverClassName: com.mysql.cj.jdbc.Driver
username: root
password:''
dbCreate: create-drop
url: jdbc:mysql://localhost:3306/master
dataSources:
ford:
dbCreate: create-drop
url: jdbc:mysql://localhost:3306/child1
audi:
dbCreate: create-drop
url: jdbc:mysql://localhost:3306/child2
# end::dataSources[]
解决方案
不用担心,我终于找到了答案,我将所有的多租户域对象打包在一个插件中以供重复使用,并且在调用项目中至少需要一个已实现多租户的域对象。测试通过的奇怪要求,但它已经奏效了。
推荐阅读
- python - 如何在 Pyqtgraph 上将平移事件从滚轮按下+拖动更改为鼠标右键单击+拖动?
- amazon-web-services - 如何将 Kinesis 数据流合并为一个以进行 Kinesis 数据分析?
- javascript - 如何以编程方式放置自定义 Leaflet.draw 形状?
- r - 在 R 中合并两个数据帧时出现 X.1、X.2、X.3
- python - 硒中的ElementClickInterceptedException
- php - 更改 /var 的权限是否安全,如果是,如何完成?如果没有,我该怎么办?
- c# - Windows 服务:运行通知方法时重新启动线程/任务会引发异常
- typescript - Conditionally type a variable if a specific parameter is given
- python - 将日期时间列转换为星期几
- webdriver-io - 如何在 webdriverIO 中使用 mock 以字符串形式发送响应