5

QuickCheck を使用してモナドおよび非モナドのコードをテストする方法を見てきましたが、エラーを処理するコード、つまりメッセージを出力してから呼び出すコードをテストするにはどうすればよいexitWithでしょうか?

4

2 に答える 2

4

最初の免責事項: 私は 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 つの欠点がありますが、それらを克服する方法は見つかりませんでした。

  1. ExitCode処理できるから例外AnExceptionを抽出する方法が見つかりませんでしたprotect。したがって、ここではすべての終了コードが同じように扱われます (それらは にマップされNothingます)。私が欲しかったのは:

    purifyException :: (a -> IO b) -> a -> IO (Either a ExitCode)
    
  2. test の I/O 動作をテストする方法が見つかりませんでした。仮定test

    test :: IO ()
    test = do
      n <- readLn
      if n > 100 then exitWith $ ExitFailure 1
                 else print n
    

    では、どのようにテストしますか?

より専門的な回答もいただければ幸いです。

于 2013-09-01T21:20:49.607 に答える
3

この種の処理には、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):
于 2013-09-01T21:37:33.857 に答える