如何模拟闭包以测试 Grails 服务结果?

Posted

技术标签:

【中文标题】如何模拟闭包以测试 Grails 服务结果?【英文标题】:How To Mock Out A Closure In Order To Test The Grails Service Result? 【发布时间】:2011-06-12 04:05:20 【问题描述】:

我想对一些类似这样的代码的返回值进行单元测试:

Groovy Service code to test:
    def findByThisAndThat(something) 
            : 
        def items = []
        sql.eachRow(query, criteriaList, 
            def item = new Item(name:it.NAME)
            items.add(item)
        )
        [items: items, whatever:whatevervalue]
    

单元测试代码计划:

   void testFindByThisAndThatReturnsAMapContainingItems()
       Sql.metaClass.eachRow =  String query, List criteria, Closure c ->

           // call closure to get passed in items list
           // add one new Item(name:"test item") to list
       

       def result = service.findByThisAndThat("", "")

       assert result.items
       assertEquals('test item', result.items[0].name)
   

我该怎么做? 谢谢!

【问题讨论】:

【参考方案1】:

像您提议的单元测试实际上只是从数据库中给出适当数据的测试,您将其正确组装到 Item 实例中。我会改用集成测试,您可以在其中访问真实数据库并使用数据库中的测试数据测试整个方法。

对数据库访问进行单元测试通常更多的是对模拟代码的测试,而不是对您的代码的测试,因此它通常没有什么用处。

【讨论】:

【参考方案2】:

通过像方法一样使用它来调用闭包。或者,您也可以使用Closure.call()。传入it 的值作为第一个参数。

Sql.metaClass.eachRow =  String query, List criteria, Closure c ->
    def mockItems = ["test item"]
    mockItems.each  item ->
        c(item)
        // c.call(item) works too
    

请注意,Sql 元类不会在测试结束时重置。我建议在测试后将其清除:

Sql.metaClass = null

【讨论】:

以上是关于如何模拟闭包以测试 Grails 服务结果?的主要内容,如果未能解决你的问题,请参考以下文章

如何模拟 acegi 身份验证服务以进行单元测试?

使用 Spock 进行 Grails 测试 - 选择哪个模拟框架?

单元测试控制器时无法模拟 Grails 服务方法 - MissingMethodException

Grails:我如何模拟被测类的其他方法,这些方法可能在测试期间被内部调用

如何在 Grails 单元测试中使用 Spock 模拟 passwordEncoder

如何使用 grails 在单元测试中模拟 springSecurityService