假設我定義了一個Haskell函數f(純函數或者動作),並且在f中的某個地方調用函數g。例如:如何模擬在Haskell中測試?
f = ...
g someParms
...
如何用模擬版本替換函數g進行單元測試?
如果我在Java中工作,g將是類SomeServiceImpl
上的一個方法,它實現接口SomeService
。然後,我會使用依賴注入來告訴f使用SomeServiceImpl
或MockSomeServiceImpl
。我不知道如何在Haskell中做到這一點。
是做引進型類SomeService的最佳方式:
class SomeService a where
g :: a -> typeOfSomeParms -> gReturnType
data SomeServiceImpl = SomeServiceImpl
data MockSomeServiceImpl = MockSomeServiceImpl
instance SomeService SomeServiceImpl where
g _ someParms = ... -- real implementation of g
instance SomeService MockSomeServiceImpl where
g _ someParms = ... -- mock implementation of g
然後,重新定義˚F如下:
f someService ... = ...
g someService someParms
...
看起來這會的工作,但我剛剛學習Haskell並想知道這是否是最好的方法?更一般地說,我喜歡依賴注入的想法,不僅僅是爲了嘲笑,而且是爲了使代碼更加可定製和可重用。一般來說,我喜歡這樣的想法:不被鎖定到一段代碼使用的任何服務的單個實現中。在代碼中廣泛使用上述技巧來獲得依賴注入的好處是否被認爲是一個好主意?
編輯:
讓我們再走一步。假設我在模塊中有一系列函數a,b,c,d,e和f,它們都需要能夠從不同模塊中引用函數g,h,i和j。假設我希望能夠模擬g,h,i和j的函數。我可以清楚地將4個函數作爲參數傳遞給a-f,但是將4個參數添加到所有函數中有點痛苦。另外,如果我需要改變任何a-f的實現來調用另一個方法,我需要改變它的簽名,這可能會產生一個令人討厭的重構練習。
任何使這種情況輕鬆工作的技巧?例如,在Java中,我可以構建一個包含所有外部服務的對象。構造函數會將這些服務存儲在成員變量中。然後,任何方法都可以通過成員變量訪問這些服務。因此,隨着方法被添加到服務中,方法簽名都不會改變。如果需要新的服務,只有構造函數方法簽名發生變化。
爲什麼要嘲諷純粹的功能? – yairchu 2009-06-13 16:16:59
好點,yairchu。你可能只會嘲笑行動。 – 2009-06-13 18:32:20
@yairchu我會這樣做是出於效率的原因。無論測試需要x或100倍的時間對生產力都非常重要。所以我想說一個因子100000000 = <一些大數>用於測試目的(因此作爲輸入/模擬到另一個測試)。但是當測試運行器運行在階乘模塊上時,該階乘100000000 = <一些大數>本身可能是一個測試。 – user239558 2010-10-28 22:04:52