簡體   English   中英

Grails 2.4.4:如何模擬域內的臨時服務?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM