Unit testing 使用多数据源进行grails单元测试
我正在尝试为grails controller编写单元测试用例,它具有以下结构:Unit testing 使用多数据源进行grails单元测试,unit-testing,grails,Unit Testing,Grails,我正在尝试为grails controller编写单元测试用例,它具有以下结构: class MyController{ def save(){ def myDomain = new MyDomain(params) business validation 1 business validation 2 myDomain.writedatasource.save() business valida
class MyController{
def save(){
def myDomain = new MyDomain(params)
business validation 1
business validation 2
myDomain.writedatasource.save()
business validation 3
business validation 4
}
}
由于单元测试不加载Datasource.groovy,因此writedatasource在单元测试期间不可用,因此“business validation 3”和“business validation 4”的测试用例在我得到时失败
groovy.lang.MissingPropertyException:没有此类属性:类:MyDomain的writedatasource
如何修改测试用例以测试验证场景3和4
测试用例很简单,如下所示:
void testSave(){
...setup...
controller.save()
assert conditions
....
}
不确定这是否能奏效,但你可以试试:
def 'the controller call the save method in writedatasource'() {
given:
def calls = 0
and:
def myDomainInstance = new MyDomain()
and:
MyDomain.metaClass.getWritedatasource = { new Object() }
and:
Object.metaClass.save = { Map attrs ->
calls++
}
when:
controller.save()
then:
calls == 1
}
但您要做的唯一一件事是测试save是否在writedatasource下调用,因此最好还有一个集成测试。如果这就是诀窍,请回答,以及他们似乎有同样的问题 解决原始问题: 我遇到了这个问题,除了在多个域上“保存”之外,我还不得不模仿很多很多方法。因此,我重写了域的getter,只返回调用域实例:
def setup() {
[MyDomain1, MyDomain2].each { Class clazz ->
mockDomain(clazz)
clazz.metaClass.getWritedatasource = {
return delegate
}
clazz.metaClass.'static'.getWritedatasource = {
return delegate
}
}
}
这也避免了我加入@DirtiesRuntime,因为我不会更新任何我想清理的元类
最重要的是,无论调用数据源是域类还是实例,都应该使用mockDomain中的GORM Fancy来修饰它,这意味着我不必模拟任何GORM方法
如果需要动态数据源怎么办?
在我的特殊情况下,数据源是可配置的,并且可能会根据环境而变化。如果遇到类似情况,可以在域映射中配置:
static mapping = {
datasources Holders.grailsApplication?.config.dynamic?.datasources
...
}
其中dynamic.datasources是数据源名称的数组。然后,在测试设置中:
def setup() {
grailsApplication.config.dynamic.datasources = ['foo', 'bar']
[MyDomain1, MyDomain2].each { Class clazz ->
mockDomain(clazz)
grailsApplication.config.dynamic.datasources.each{
clazz.metaClass."get${it.capitalize()}" = {
return delegate
}
clazz.metaClass.'static'."get${it.capitalize()}" = {
return delegate
}
}
}
}
有趣的问题。您将不得不模拟数据源,或者如果您编写一个集成测试,那就更好了集成测试肯定会完成这项工作,但我们有几个这样的场景实例(几乎80%的组件),因此如果我们为每个场景编写集成测试,那么基本上就不会有任何单元测试。即使我们模拟数据源,您如何将其附加到myDomain,以便控制器可以使用它使myDomain.writedatasource.save()工作。我刚刚意识到我使用Spock做了一个示例,但我认为您可以承担它的重要部分。谢谢您的帮助。我在字符串上尝试元类,但新对象效果更好。下面是我使用的:Object.metaClass.save={args->return true}myDomain.metaClass.rmprw=new Object(),只是为了避免混淆,它是writedasource而不是rmprw。Object.metaClass.save={args->return true}myDomain.metaClass.writedasource=new Object()这是一个很好的解决方案,不过在我用注释正确定义安装程序块之前,它对我不起作用@在void setup()之前{…}