QuickCheck を使用してモナドおよび非モナドのコードをテストする方法を見てきましたが、エラーを処理するコード、つまりメッセージを出力してから呼び出すコードをテストするにはどうすればよいexitWith
でしょうか?
2 に答える
最初の免責事項: 私は QuickCheck の専門家ではなく、質問の前にモナド チェックの経験がありませんでしたが、stackoverflow は新しいことを学ぶ機会だと考えています。これがもっとうまくできるという専門家の回答があれば、私は削除します。
test
を使用して例外をスローできる関数があるとしexitWith
ます。これがあなたがそれをテストできると思う方法です。重要な機能はprotect
で、例外をキャッチして、テストできるものに変換します。
import System.Exit
import Test.QuickCheck
import Test.QuickCheck.Property
import Test.QuickCheck.Monadic
test :: Int -> IO Int
test n | n > 100 = do exitWith $ ExitFailure 1
| otherwise = do print n
return n
purifyException :: (a -> IO b) -> a -> IO (Maybe b)
purifyException f x = protect (const Nothing) $ return . Just =<< f x
testProp :: Property
testProp = monadicIO $ do
input <- pick arbitrary
result <- run $ purifyException test $ input
assert $ if input <= 100 then result == Just input
else result == Nothing
私が見る限り、これには 2 つの欠点がありますが、それらを克服する方法は見つかりませんでした。
ExitCode
処理できるから例外AnException
を抽出する方法が見つかりませんでしたprotect
。したがって、ここではすべての終了コードが同じように扱われます (それらは にマップされNothing
ます)。私が欲しかったのは:purifyException :: (a -> IO b) -> a -> IO (Either a ExitCode)
test の I/O 動作をテストする方法が見つかりませんでした。仮定
test
:test :: IO () test = do n <- readLn if n > 100 then exitWith $ ExitFailure 1 else print n
では、どのようにテストしますか?
より専門的な回答もいただければ幸いです。
この種の処理には、QuickCheckexpectFailure
関数を使用できます。この単純な (そして推奨されない) エラー処理フレームワークを取り上げます。
import System.Exit
import Test.QuickCheck
import Test.QuickCheck.Monadic
handle :: Either a b -> IO b
handle (Left _) = putStrLn "exception!" >> exitWith (ExitFailure 1)
handle (Right x) = return x
いくつかのダミー関数を作成します。
positive :: Int -> Either String Int
positive x | x > 0 = Right x
| otherwise = Left "not positive"
negative :: Int -> Either String Int
negative x | x < 0 = Right x
| otherwise = Left "not negative"
これで、エラー処理のいくつかのプロパティをテストできます。まず、Right
値によって例外が発生しないようにする必要があります。
prop_returnsHandledProperly (Positive x) = monadicIO $ do
noErr <- run $ handle (positive x)
assert $ noErr == x
-- Main*> quickCheck prop_returnsHandledProperly
-- +++ OK, passed 100 tests.
Lefts
例外が発生するはずです。expectFailure
最初に追加されていることに注意してください。
prop_handlesExitProperly (Positive x) = expectFailure . monadicIO $
run $ handle (negative x)
-- Main*> quickCheck prop_handlesExitProperly
-- +++ OK, failed as expected. Exception: 'exitWith: invalid argument (ExitFailure 0)' (after 1 test):