[英]Grails 2.4.4 : How do mock a transient service inside a domain?
我已經嘗試了兩天了,我真的很沮喪。 我有一個帶有用於自定義驗證的服務的域對象。 域如下所示:
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
}
}
現在,我有另一個服務,它只是保存了一個Llama對象列表。 看起來像這樣:
class LlamaFactoryService {
public void createLlamas(List<String> llamaNames) {
llamaNames.each { name ->
new Llama(name: name).save()
}
}
}
在我的測試中。 我不斷收到此錯誤:
Failure: createLlamas should create Llammas (com.myLlamaProject.LlamaFactoryServiceSpec)
| java.lang.NullPointerException: Cannot invoke method myFetcherService on null object
我不明白 在我的測試中,在“給定”部分為服務添加了metaClass。 當它嘗試保存時,表明該服務為空。 這是我的測試結果:
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()
上使用metaClass,例如:
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
如果將服務注入metaClass不起作用( 此處建議 ),則您始終可以嘗試在單元測試本身中使用defineBeans {}閉包( http://www.block-consult.com/blog/2011/ 08/17 /將彈簧安全服務注入到控制器單元測試的域類中 )。
因此,您可以嘗試:
defineBeans {
myFetcherService(MockMyFetcherService)
}
其中MockMyFetcherService
是在定義測試的同一文件中定義的。 這是此處遵循的方法:
有關更多Spock交互的示例,請參見此處 。
如果您使用的是Grails 2.4.3或更低版本,則需要將CGLIB放入BuildConfig.groovy中,但我在這里看到它已經在2.4.4中為您完成,因此您應該可以只使用Mock(classname)
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.