2012-11-02 20 views
7

我現在有下面的測試代碼:有沒有可能在IO之外的monad中使用帶有測試框架的HUnit?

testUpdate :: Test 
testUpdate = testCase "update does change artist" $ do 
    (created, Just revised, parents) <- mbTest $ do 
    Just editor <- fmap entityRef <$> findEditorByName "acid2" 

    created <- create editor startWith 
    let artistId = coreMbid created 

    newRev <- update editor (coreRevision created) expected 

    editId <- openEdit 
    includeRevision editId newRev 
    apply editId 

    found <- findLatest artistId 
    parents <- revisionParents newRev 

    return (created, found, parents) 

    coreData revised @?= expected 

    assertBool "The old revision is a direct parent of the new revision" $ 
    parents == [coreRevision created] 

    where 
    startWith = ... 
    expected = ... 

這有點兒工作,但它的混亂。我寧願寫一些東西,而不必返回測試中的各種東西,而是在有意義的地方給出斷言。

我看到有Assertable類,但似乎我可能不得不重新創建一堆東西。

+0

偉大的問題,我記得想知道爲什麼當我第一次使用它時,爲什麼每個事物都需要IO。 –

+0

monad支持'liftIO'嗎? – hammar

+0

@hammar它的確如此,我不確定我是如何錯過這個事實的,即我需要做的就是用'liftIO'提升這些測試。但是,我會留下這個問題,也許還有其他方法:) – ocharles

回答

1

爲什麼不只是讓你的monad返回一個IO計算類型IO a,這是一個值? 由於在您的評論,其中單子是MonadIO的一個實例是微不足道的情況下, 假設單子允許純計算:

newtype M a = M {runM :: ....} 
instance Monad M where 
    ... 

makeTest :: M Assertion 
makeTest = do 
    created <- .. 
    found <- .. 
    parents <- .. 
    let test1 = coreData revised @?= expected 
    ... 
    let test2 = assertBool "The old revision..." $ 
        parents == [coreRevision create] 

    return $ test1 >> test2 

testUpdate :: Test 
testUpdate = testCase "update does change artist" $ runM makeTest 

一個好處是,你可以通過一個一元迴歸測試集合計算, 就像你在列表monad中一樣。

+0

我不太喜歡這個,因爲所有斷言的運行時間比取決於斷言的代碼晚得多。這可能意味着斷言實際上不會失敗,因爲代碼本身可能已經拋出異常,因爲斷言不成立。 – ocharles

+0

你是否認爲在我的例子中'test1'和'test2'之間的代碼應該能夠捕獲這些測試引發的異常? 但是,在這種情況下,您的monad必須是MonadIO的一個實例,除非您作弊(即使用'unsafe *'),因爲Haskell純代碼無法捕獲異常。正如你所說,這種情況是微不足道的解決'升'。 也許你忘記了Haskell是一種_lazy_語言?懶惰語言的工作是確保評估順序無關緊要(IO事件除外)。我真的很想看到一個例子,其中'liftIO'和我的解決方案都不起作用。 – mnish

相關問題