Unit testing Grails2.4.4:如何模拟域内的临时服务?

Unit testing Grails2.4.4:如何模拟域内的临时服务?,unit-testing,grails,testing,Unit Testing,Grails,Testing,两天来我一直在努力解决这个问题,我真的被困住了,很沮丧。我有一个域对象,其中包含一个用于自定义验证的服务。该域如下所示: class Llama { String name transient myFetcherService static transients = [ 'myFetcherService' ] static constraints = { name validator: { val, obj ->

两天来我一直在努力解决这个问题,我真的被困住了,很沮丧。我有一个域对象,其中包含一个用于自定义验证的服务。该域如下所示:

class Llama { 
String name
transient myFetcherService

static transients = [
            'myFetcherService'
    ]

static constraints = {
        name validator: { val, obj ->
            if (obj.nameExists(val) == true) {
                //return some error here.
            }
        }
    }

protected boolean nameExists(String name) {
        List<Llama> llamasList = myFetcherService.fetchExistingLlamasByName(name)

        if (llamasList.isEmpty()) {
            return false
        }

        return true
    }
}
class LlamaFactoryService {

   public void createLlamas(List<String> llamaNames) {
     llamaNames.each { name ->
         new Llama(name: name).save()
     }
   }

}
我不明白。在我的测试中,在“给定”部分为服务添加了一个元类。当它试图保存时,它告诉我们服务为空。这就是我的测试结果:

given:
def myFetcherService = mockFor(MyFetcherService)   
myFetcherService.demand.fetchExistingLlamasByName {def name -> return []}
Llama.metaClass.myFetcherService = myFetcherService.createMock()

when:
service.createLlamas(['Pablo','Juan','Carlos'])

then:
//some validations here....
我还尝试在方法
nameExists()
上使用元类,比如:

Llama.metaClass.myFetcherService = { def name -> false }
,但它给了我与上面一样的nullPointerException。有人能给我指一下正确的方向吗?我有点卡住了(


提前感谢您的阅读和帮助。

您正在使用单元测试,单元测试的一般规则是,bean通常不是为您创建的,因此您需要自己注入它们

(编辑代码以反映我误读问题的事实) 我认为您需要一种测试模式,比如:

given:
def mockMyFetcherService = Mock(MyFetcherService) // create the mock
Llama.metaClass.getMyFetcherService = { mockMyFetcherService } // inject the dependency
def returnList = []  // let's just define this here and you can re-use this pattern in other tests more easily

when:
service.createLlamas(['Pablo','Juan','Carlos'])

then:
// tell Spock what you expect to have happen with your Mock - return the List you defined above
3 * mockFetcherService.fetchExistingLlamasByName(_) >> returnList
如果向元类中注入服务不起作用(),您可以尝试在单元测试本身()中使用defineBeans{}闭包

因此,您可以尝试:

defineBeans {
  myFetcherService(MockMyFetcherService)
}
其中,
MockMyFetcherService
在定义测试的同一文件中定义。这是一种方法:

有关更多Spock交互的示例,请参见


如果您使用的是Grails 2.4.3或更低版本,则需要将CGLIB放在BuildConfig.groovy中,但我发现在2.4.4中已经为您完成了这项工作,所以您只需使用
Mock(classname)就可以了

在这里添加相关标记,无论是单元测试还是集成测试。这是一个单元测试。2.3.11中也有thanksWorks。因此,我将MyFetcherService注入正在使用域的服务中?而不是在MyFetcherService所在的域中?从来没有想过……我正在使用grails 2.4.4。我会尝试一下。感谢您的响应。不会rk man.myFetcherService在域中使用,而不是在服务中。我得到了一个.MissingPropertyException:没有这样的属性:myFetcherService for class LlamaFactoryService.:\对不起,我错了,我错了,我错了,我以为你在服务中使用服务,而不是域中的服务。让我用另一个建议回复你稍后继续。@CancerMan希望新的建议有用,我对其中一个/两个如何为您工作感兴趣,因为我仍在学习Grails。
defineBeans {
  myFetcherService(MockMyFetcherService)
}