QuickCheckでリーダーモナドを使用する|monadicIO
-
21-12-2019 - |
質問
QuickCheckを使用するHaskellプログラムにcli引数として整数を渡したいと思います / monadicIO
.その整数は、内部で使用されようとしています assert
テストをカスタマイズ可能にするため。問題は、整数値を解析すると main
, 、私はそれを内部に渡す方法がわかりません monadicIO
のような醜いものを使わずに呼び出すことができます。 IORef
.私はエレガントな解決策があるかもしれないと思うだろう Reader
モナドが、私はそれを動作させるための解決策を見つけることができませんでした quickCheck
その引数に剛性があります。何か考えは?
後の編集1: 要求されたように、私はこれを試している実際のコードを添付して失敗しています。コメントアウトされた行は、私の失敗した試みを表しています。背景:テストスイートは、QuickCheckによって生成されたランダム化された入力のSHA512を計算する非常に単純なリモートエンドポイントを実行することを目的としリモートエンドポイントはPython/Flaskベースです。
後で@user2407038に応答して2を編集します: 私は作ることができました propHasExpectedLengthCeiling
Int型の追加の引数を取りますが、 quickCheck
それに対してランダムな値を生成しますが、それは私が望んでいることではありません。私の目標は、 maxSegmentLengthCeiling
私はコマンドライン引数から取って、それを使用していること let testPassed = actualMaxSegmentLength <= maxSegmentLengthCeiling
の内部 monadicIO
ブロック。今すぐ maxSegmentLengthCeiling
これは、値を変更するたびにコードを再コンパイルする必要があることを意味します。私はまだ含まれるコードを持っていません IORef
それが最後の手段であり、私の質問の本質は、どのように行くのを避けるかということです IORef
ルート。
import qualified Data.ByteString.Lazy.Char8 as LC
import Control.Applicative ( (<$>) )
import Data.Function ( on )
import Data.List ( groupBy )
import Data.Char ( isDigit )
--import Safe ( headMay
-- , readMay
-- )
--import System.Environment ( getArgs )
import Network.HTTP.Conduit ( simpleHttp )
import Test.QuickCheck ( Arbitrary
, Property
, arbitrary
, choose
, frequency
, quickCheckWith
, stdArgs
, vectorOf
)
import Test.QuickCheck.Test ( Args
, maxSuccess
)
import Test.QuickCheck.Monadic ( assert
, monadicIO
, run
)
newtype CustomInput = MkCustomInput String deriving Show
instance Arbitrary CustomInput where
arbitrary =
let
genCustomInput = vectorOf 20
$ frequency [ (26, choose ('0','9'))
, (10, choose ('a','z'))
]
in
MkCustomInput <$> genCustomInput
maxSegmentLengthCeiling :: Int
maxSegmentLengthCeiling = 22
urlPrefix :: String
urlPrefix = "http://192.168.2.3:5000/sha512sum/"
propHasExpectedLengthCeiling :: CustomInput -> Property
propHasExpectedLengthCeiling (MkCustomInput input) = monadicIO $ do
testPassed <- run $ do
response <- simpleHttp $ urlPrefix ++ input
let stringResponse = LC.unpack response
let brokenDownStringResponse = groupBy ( (==) `on` isDigit ) stringResponse
let actualMaxSegmentLength = maximum $ map length brokenDownStringResponse
let testPassed = actualMaxSegmentLength <= maxSegmentLengthCeiling
putStrLn ""
putStrLn ""
putStrLn $ "Input: " ++ input
putStrLn $ "Control sum: " ++ stringResponse
putStrLn $ "Breakdown: " ++ show brokenDownStringResponse
putStrLn $ "Max. length: " ++ show actualMaxSegmentLength
putStrLn $ "Ceiling: " ++ show maxSegmentLengthCeiling
putStrLn $ "Test result: " ++ if testPassed then "Pass" else "Fail"
putStrLn ""
putStrLn ""
return testPassed
assert $ testPassed
customArgs :: Args
customArgs = stdArgs { maxSuccess = 1000000 }
--readMayAsInt :: String -> Maybe Int
--readMayAsInt = readMay
main :: IO ()
main =
--main = do
-- cliArgs <- getArgs
-- let ceilingInputMay = headMay cliArgs >>= readMayAsInt
-- maxSegmentLengthCeiling <- case ceilingInputMay of
-- (Just lengthCeiling) -> return lengthCeiling
-- Nothing -> error "No valid number given"
quickCheckWith
customArgs
propHasExpectedLengthCeiling
解決
作る maxSegmentLengthCeiling
にパラメータを指定します。 propHasExpectedLengthCeiling
:
propHasExpectedLengthCeiling :: Int -> CustomInput -> Property
そしてそれを次のように呼び出します
main = do
[n] <- getArgs
quickCheckWith customArgs (propHasExpectedLengthCeiling (read n))