基於SO問題13350164 How do I test for an error in Haskell?,我試圖編寫一個單元測試,它聲明給定無效輸入,遞歸函數引發異常。我採用的方法適用於非遞歸函數(或者當第一次調用引發異常時),但只要異常發生在調用鏈中更深處,斷言就會失敗。Haskell異常和單元測試
我讀過問題6537766 Haskell approaches to error handling的優秀答案,但不幸的是,對於我的學習曲線來說,這個建議有點過於通用。我的猜測是,這裏的問題與惰性評估和非純測試代碼相關,但我會很感激專家的解釋。
在這種情況下(例如Maybe
或Either
),我應該採取不同的方法來處理錯誤嗎?還是有合理的方法可以使測試用例在使用這種風格時正常工作?
這是我想出的代碼。前兩個測試案例成功,但第三個測試案例以"Received no exception, but was expecting exception: Negative item"
失敗。
import Control.Exception (ErrorCall(ErrorCall), evaluate)
import Test.HUnit.Base ((~?=), Test(TestCase, TestList))
import Test.HUnit.Text (runTestTT)
import Test.HUnit.Tools (assertRaises)
sumPositiveInts :: [Int] -> Int
sumPositiveInts [] = error "Empty list"
sumPositiveInts (x:[]) = x
sumPositiveInts (x:xs) | x >= 0 = x + sumPositiveInts xs
| otherwise = error "Negative item"
instance Eq ErrorCall where
x == y = (show x) == (show y)
assertError msg ex f =
TestCase $ assertRaises msg (ErrorCall ex) $ evaluate f
tests = TestList [
assertError "Empty" "Empty list" (sumPositiveInts ([]))
, assertError "Negative head" "Negative item" (sumPositiveInts ([-1, -1]))
, assertError "Negative second item" "Negative item" (sumPositiveInts ([1, -1]))
]
main = runTestTT tests
'Maybe'是'MonadPlus'!更清楚地寫'sumPositives xs = do {guard $ not(null xs);守護$ all(> 0)xs; return(sum xs)}'imo。 – dave4420 2013-02-10 22:47:46
是的,我原本打算這麼做 - 我一直使用上面的「guard」這個詞。在我的天真單子代碼中看到「管道」後,我被激勵把它寫成一個Kleisli組合,但它絕對沒有價值。 – 2013-02-10 23:02:42