Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Unit testing 使用多数据源进行grails单元测试_Unit Testing_Grails - Fatal编程技术网

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

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

我正在尝试为grails controller编写单元测试用例,它具有以下结构:

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()之前{…}