2012-12-28 83 views
4

我正在研究一個新鮮的Grails項目,並且最近注意到Spring Security Core生成的User類中的默認約定現在通過beforeInsert/Update事件自動編碼密碼。這是一種乾淨,乾淨的編碼方式,也使得忘記這麼做成爲不可能。但是,現在當試圖寫一些使用所述User類的單元測試時,我發現我必須模擬springSecurityService(由於編碼),或者更優選地(並且乾淨地),我' d只需重寫beforeInsert/Update閉包,其中一個不執行任何操作。通常在Groovy一個可以覆蓋使用ExpandoMetaClass,鼻翼的方法...Grails GORM領域類的單元測試重寫事件關閉

User.metaClass.beforeInsert = { /* do nothing */ } 

...但我發現,原來beforeInsert繼續在創建並保存新的用戶調用。這反過來導致我的單元測試爆炸。對我來說,解決這個問題並嘲笑服務是微不足道的,但上面的應該工作。我錯過了什麼嗎? GORM的事件關閉有什麼不同,我沒有采取?

+0

另外一點需要注意的,我有一個@Mock([用戶])在我的測試註解。這可能與奇怪的行爲有關,但僅僅是一種預感。 – James

+0

是實例上的expando方法嗎? //問它永遠不會太晚:) –

+0

你爲什麼這麼想,那嘲笑springSecurityService並不是這樣做的首選方式?我的意思是,在思考依賴注入時,首先考慮的事情之一就是:外部化依賴管理,因此能夠爲測試目的創建存根/模擬。在我看來,改變用戶的metaClass在任何方面都不是很清楚。 –

回答

3

爲了提高性能Grails使用反射直接與緩存方法處理調用事件,而不是Groovy的元層。原因是,如果您要保存數百個域實例,那麼如果Grails必須通過Groovy的每個事件的元層才能嚴重影響性能。

有辦法解決這個問題,比如定義你自己的User類,根據你的測試設置的系統/環境屬性來禁用事件,但是目前沒有辦法通過元編程來覆蓋這些方法。

+0

我知道這是一個老問題。有什麼方法可以訪問緩存層來覆蓋該方法嗎? – christopher

1

beforeInsert閉包實際上不僅是像toString()或save()這樣的方法,而且也是Gorm支持的預定義事件。重寫該方法不會阻止Gorm觸發導致原始過程的PreInsert事件。

+2

我知道beforeInsert是一個事件(參見我的最後一句話),但關閉僅僅決定了當給定模型的事件被觸發時*發生了什麼。重寫它應該允許一個人改變那個行爲,就像其他任何東西一樣。我並沒有試圖阻止GORM發起事件,我試圖改變事件發生時會發生的事情。 – James

0

如果需要,你可以用一個私有方法替換beforeInsert代碼,然後重寫私有方法