Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/2.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 如何在Spock测试中模拟模拟类的局部变量?_Unit Testing_Variables_Grails_Mocking_Spock - Fatal编程技术网

Unit testing 如何在Spock测试中模拟模拟类的局部变量?

Unit testing 如何在Spock测试中模拟模拟类的局部变量?,unit-testing,variables,grails,mocking,spock,Unit Testing,Variables,Grails,Mocking,Spock,假设我在服务中有以下方法: private void deleteItems(List<Item> itemsToDelete) { def sql = new Sql(dataSource) itemsToDelete?.each { Item item -> sql.execute("DELETE FROM owner_item WHERE item_id = ${item.id}") item.delete(flush: t

假设我在服务中有以下方法:

private void deleteItems(List<Item> itemsToDelete) {
    def sql = new Sql(dataSource)
    itemsToDelete?.each { Item item ->
        sql.execute("DELETE FROM owner_item WHERE item_id = ${item.id}")
        item.delete(flush: true, failOnError: true)
        flushDatabaseSession();
    }
}

这里您要做的是模拟依赖项(
Sql
)的依赖项(
DataSource
)。这通常会导致一种情况,即您无法100%了解
Sql
如何与
DataSource
对象交互。如果
Sql
在版本更新中更改了与
Datasource
的私有交互,则必须处理这种情况

您应该直接调用
Sql
类,而不是模拟依赖项的依赖项。为此,
sql
必须是某种明确的依赖项,您可以通过DI或方法参数接收。在这种情况下,您可以像这样模拟
execute
调用(选择a的方式,但也可以使用
Map
或来自Spock的模拟内容):

考虑到整个测试用例,我认为有两个主要问题

第一个问题是,当你问自己,通过模仿整个sql的东西,你到底得到了什么样的确定性。在这种情况下,您在这里要做的唯一一件事就是与db交互。当你嘲笑这件事的时候,你就没有什么可以测试的了。没有多少有条件的东西或任何东西应该由单元测试来支持。因此,我建议只为这个测试用例编写集成规范,在这个测试用例中,您可以使用类似H2DB的东西进行测试

第二件事是,实际上根本不需要Sql操作。您可以配置GORM和Hibernate,以便在删除项目时自动透明地删除项目所有者。对于这一点,请查看GORM的文档(尤其是),或直接在中查看

总而言之:使用
cascade:'delete'
和适当的集成测试,您就有了大量的确定性和较少的样板代码

@TestFor(ItemService)
@Mock([Item])
@Build([Item])
class SubjectServiceSpec extends Specification {

...

    def "delete items"() {
        given:
        Item item1 = Item.build().save(flush: true)
        Item item2 = Item.build().save(flush: true)
        Item.count() == 2
        DataSource mockDataSource = Mock()
        service.dataSource = mockDataSource
        1 * deleteItems

        when:
        service.deleteItems([item1, item2])

        then:
        Item.count() == 0
    }
}
given:
def sqlMock = new Expando()
sqlMock.execute = { return 'what ever you want or nothing, because you mock a delete operation' }
service.sql = sqlMock

when:
service.deleteItems([item1, item2])

then:
assertItemsAreDeletedAndTheOwnerAsWell()