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()