使用多个数据源进行grails单元测试

时间:2014-01-16 20:00:44

标签: unit-testing grails

我正在尝试为grails控制器编写单元测试用例,该控制器具有以下结构:

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 在单元测试期间不可用,因此“业务验证3”和“业务验证4”的测试用例失败,因为我< / p>

groovy.lang.MissingPropertyException:没有这样的属性:类的writedatasource:MyDomain

如何修改测试用例以测试验证方案3和4?

测试用例很简单,如下所示:

void testSave(){
    ...setup...
    controller.save()
    assert conditions
    ....

}

2 个答案:

答案 0 :(得分:1)

不确定这是否可以解决问题,但您可以尝试:

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
}

但你唯一要做的就是测试在writedatasource下调用save,所以最好也进行集成测试。如果这样做,请在http://grails.1312388.n4.nabble.com/Mocking-in-a-unit-test-a-domain-object-multiple-datasources-td4646054.html回答,因为他们似乎有同样的问题。

答案 1 :(得分:1)

解决原始问题:

我遇到了这个问题,不得不嘲笑许多方法,而不仅仅是拯救&#39;在多个域上。所以相反,我覆盖了我的域的getter,只是简单地返回调用域实例:

def setup() {
    [MyDomain1, MyDomain2].each { Class clazz ->
        mockDomain(clazz)
        clazz.metaClass.getWritedatasource = { 
            return delegate
        }
        clazz.metaClass.'static'.getWritedatasource = {
            return delegate
        }
    }
}

这也使我免于包含@DirtiesRuntime,因为我没有更新任何我想要清理的metaClass。

最重要的是,无论是调用数据源,无论是域类还是实例,它都应该使用mockDomain的GORM功能进行修饰,这意味着我不必模拟任何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
            }
        }
    }
}