2011-06-21 26 views
0

編輯:請讓我清楚,我問如何在Grails中使用Spring依賴注入,而不是Grails的元類功能或new()。如何選擇性地設置屬性使用依賴注入在grails服務單元測試

我有一個用於分析日誌文件的grails服務。在服務內部,我使用當前時間處理很多事情。對於單元測試,我有幾個使用此服務解析的示例日誌文件。這些顯然有時間。

我想要我的服務,在單元測試期間認爲當前時間不超過我的示例日誌文件中最後一條日誌語句後的幾個小時。

所以,我願意這樣:

 

class MyService { 
    def currentDate = { -> new Date() } 

    def doSomeStuff() { 
     // need to know when is "right now" 
     Date now = currentDate() 
    } 
} 
 

所以,我希望能夠做的是注射的currentdate或設置爲其他一些硬編碼時間,像

currentDate = { -> new Date(1308619647140) }

有沒有辦法做到這一點與我的單元測試中的一些mockWhatever方法? Google Guice的這種功能非常簡單,但我不知道如何在Spring中做到這一點。

這是很令人沮喪的是,當我谷歌「的Grails依賴注入」所有我看到的是的


class SomeController { 
    // wow look how amazing this is, it's injected automatically!! 
    // isn't spring incredible OMG! 
    def myService 
} 

感覺就像所有這一切顯示的是,我不必鍵入新的例子...( )

我在哪裏可以告訴它,當環境中平等的測試,那麼這樣做:


currentDate = { -> new Date(1308619647140) } 

我是不是停留在我的測試手動設置該屬性?

我不想創建一個「timeService」,因爲這看起來很愚蠢,因爲我只想要1個小小的改變。

+0

感謝您的答案迄今傢伙,但我真的想知道如何B/C,因爲它似乎這樣做使用Spring/Grails的依賴注入對我來說,DI的全部目的就是這種確切的上下文行爲。是否真的沒有合理的方式來做到這一點 - 根據哪個環境(測試,生產或開發)與依賴注入加載不同的屬性?如果你不能做到這一點,那麼它究竟是什麼? – jpswain

+0

在單元測試期間,Grails將**不會**注入依賴關係。它不會在SUT類的集成測試期間注入它們。請參閱http://grails.org/doc/latest/guide/9.%20Testing.html#9.1%20Unit%20Testing。也許這就是你要找的東西? http://grails.org/doc/latest/guide/14.%20Grails%20and%20Spring.html#14.2%20Configuring%20Additional%20Beans查看Spring DSL的部分。然後,再次,這將**不**工作在單元測試。 –

+0

也許你可以發佈相應的Google Guice代碼來實現你想要實現的目標? –

回答

1

感謝您的幫助球員。我能想出在這種情況下使用Spring DI最好的解決辦法是做

resources.groovy

這些下面是兩個解決辦法,我發現:
1:如果我想的timeNowService是交換用於測試目的無處不在:

import grails.util.GrailsUtil 

// Place your Spring DSL code here 
beans = { 
    if (GrailsUtil.environment == 'test') { 
     println ">>> test env" 
     timeNowService(TimeNowMockService) 
    } else { 
     println ">>> not test env" 
     timeNowService(TimeNowService) 
    } 
} 


2:我能做到這一點,如果我只希望這個更改應用於此特定的服務:

import grails.util.GrailsUtil 

// Place your Spring DSL code here 
beans = { 

    if (GrailsUtil.environment == 'test') { 
     println ">>> test env" 
     time1(TimeNowMockService) 
    } else { 
     println ">>> not test env" 
     time1(TimeNowService) 
    } 
    myService(MyService) { 
     diTest = 'hello 2' 
     timeNowService = ref('time1') 
    } 
} 


在這兩種情況下,我會通過調用 timeNowService.now()使用該服務。 的一個怪了,很無奈的事情對我來說是我能不能做到這一點:

import grails.util.GrailsUtil 
// Place your Spring DSL code here 
beans = { 
    if (GrailsUtil.environment == 'test') { 
     println ">>> test env" 
     myService(MyService) { 
      timeNow = { -> new Date(1308486447140) } 
     } 
    } else { 
     println ">>> not test env" 
     myService(MyService) { 
      timeNow = { -> new Date() } 
     } 
    } 
} 

事實上,當我想,我也有過一個虛擬值,像dummy = 'hello 2'然後的默認值dummy = 'hello'在myService類本身。當我在第三個例子中設置了虛擬值時,它默默地未能設置,顯然B/c timeNow私下裏吹了一些東西。

我很想知道是否有人能解釋爲什麼會失敗。

感謝您的幫助球員和抱歉,感到不耐煩......

1

Groovy是一種動態語言,因此它可以讓你做幾乎你問什麼:

class MyServiceTests extends GrailsUnitTestCase { 
    def testDoSomeStuff() { 
     def service = new MyService() 
     service.currentDate = { -> new Date(1308619647140) } 

     // assert something on service.doSomeStuff() 
    } 
} 

請記住,這只是修改了service實例,而不是類。如果您需要修改課程,您需要使用metaClass。看看this postmrhaki

另一種選擇是將當前日期作爲參數doSomeStuff()。這樣你就不需要修改你的服務實例。

0

由於Groovy是動態的,您可以從您的服務中刪除currentDate()方法,並將其替換爲適合您需要的方法。您可以在安裝測試期間在運行時執行此操作。

此前有實例化的MyService的實例,有以下代碼執行:

MyService.metaClass.currentDate << {-> new Date(1308619647140) } 

這樣,您就可以在所有的測試一致的行爲。然而,如果你願意,你可以通過閉包來覆蓋實例方法,它可以完成相同的技巧。

讓我知道它是怎麼回事。

VincentGiguère