QuickCheckも動かす:test-framework
Haskellを使う段階においては、HUnitよりもQuickCheckが必要なんじゃないかと思います。だから本当はQuickCheck用のテストと少しのHUnitテストを書くことになると思うのですが、これを同時に扱うライブラリにtest-frameworkがあります。
まず挿入ソートを前の記事のようにHUnitを使って書いてみます。出来上がったのは次のようなものです。
[test_sort.hs]
module SortTests where import MySort import Test.HUnit test_insert1, test_insert2, test_isort1, test_isort2,test_isort3, test_isort4 :: Test test_insert1 = TestCase(assertEqual "" (insert 1 []) [1]) test_insert2 = TestCase(assertEqual "" (insert 2 [1,3,5]) [1,2,3,5]) test_isort1 = TestCase(assertEqual "" (isort []) []) test_isort2 = TestCase(assertEqual "" (isort [1]) [1]) test_isort3 = TestCase(assertEqual "" (isort [2,1]) [1,2]) test_isort4 = TestCase(assertEqual "" (isort [3,2,1,4]) [1,2,3,4]) tests :: Test tests = TestList [ TestLabel "test_insert1" test_insert1, TestLabel "test_insert2" test_insert2, TestLabel "test_isort1" test_isort1, TestLabel "test_isort2" test_isort2, TestLabel "test_isort3" test_isort3, TestLabel "test_isort4" test_isort4 ] main = runTestTT tests
[sort.hs]
module MySort where insert :: Int -> [Int] -> [Int] insert x [] = [x] insert x yys@(y:ys) | x < y = x:yys | otherwise = y: insert x ys isort :: [Int] -> [Int] isort [] = [] isort (x:xs) = insert x (isort xs)
うーん、これだけではこれで良いのか不安です。それで、QuickCheckを使って複数のインプットを使ったテストをします。QuickCheckはQuickCheckで書くこともできますが、一緒に扱えるtest-frameworkの方がおそらく便利でしょう。テストをtest-framework用に書き換えてみましょう。
module SortTests where import MySort import Test.Framework (defaultMain, testGroup) import Test.Framework.Providers.HUnit import Test.HUnit main = defaultMain tests tests = [testGroup "HUnitTests" [ testCase "test_insert1" test_insert1, testCase "test_insert2" test_insert2, testCase "test_isort1" test_isort1, testCase "test_isort2" test_isort2, testCase "test_isort3" test_isort3, testCase "test_isort4" test_isort4 ] ] test_insert1 = assertEqual "" (insert 1 []) [1] test_insert2 = assertEqual "" (insert 2 [1,3,5]) [1,2,3,5] test_isort1 = assertEqual "" (isort []) [] test_isort2 = assertEqual "" (isort [1]) [1] test_isort3 = assertEqual "" (isort [2,1]) [1,2] test_isort4 = assertEqual "" (isort [3,2,1,4]) [1,2,3,4]
ではリロードしてテストを実行してみます。
[star]SortTests> main
Loading package syb ... linking ... done.
Loading package base-3.0.3.0 ... linking ... done.
Loading package array-0.2.0.0 ... linking ... done.
Loading package containers-0.2.0.0 ... linking ... done.
Loading package bytestring-0.9.1.4 ... linking ... done.
Loading package old-locale-1.0.0.1 ... linking ... done.
Loading package old-time-1.0.0.1 ... linking ... done.
Loading package random-1.0.0.1 ... linking ... done.
Loading package regex-base-0.72.0.2 ... linking ... done.
Loading package regex-posix-0.72.0.3 ... linking ... done.
Loading package time-1.1.2.2 ... linking ... done.
Loading package unix-2.3.1.0 ... linking ... done.
Loading package ansi-terminal-0.5.5 ... linking ... done.
Loading package ansi-wl-pprint-0.5.1 ... linking ... done.
Loading package extensible-exceptions-0.1.1.2 ... linking ... done.
Loading package hostname-1.0 ... linking ... done.
Loading package xml-1.3.7 ... linking ... done.
Loading package test-framework-0.3.3 ... linking ... done.
Loading package test-framework-hunit-0.2.6 ... linking ... done.
HUnitTests:
test_insert1: [OK]
test_insert2: [OK]
test_isort1: [OK]
test_isort2: [OK]
test_isort3: [OK]
test_isort4: [OK]Test Cases Total
Passed 6 6
Failed 0 0
Total 6 6
[star3] Exception: ExitSuccess
QuickCheckのテストを追加します。
module SortTests where import MySort import Test.Framework (defaultMainWithArgs, testGroup) .. import Test.Framework.Providers.QuickCheck (testProperty) import Test.QuickCheck main = defaultMainWithArgs tests .. testCase "test_isort4" test_isort4, testCase "test_is_sorted1" test_is_sorted1, testCase "test_is_sorted2" test_is_sorted2, testCase "test_is_sorted3" test_is_sorted3, testCase "test_is_sorted4" test_is_sorted4 ], testGroup "QuickTests" [ testProperty "isort" prop_isort1 ] ] .. test_is_sorted1 = assertBool "" (isSorted []) test_is_sorted2 = assertBool "" (isSorted [4]) test_is_sorted3 = assertBool "" (isSorted [1,2,3,4]) test_is_sorted4 = assertBool "" (not (isSorted [3,2,1,4])) prop_isort1 xs = isSorted(isort xs) == True where types = (xs :: [Int])
これでテスト側は準備OKです。sort.hsにisSortedを実装したとして、テストを実行します。
SortTests> main ["-a 5000", "-j 2"]
HUnitTests:
test_insert1: [OK]
test_insert2: [OK]
test_isort1: [OK]
test_isort2: [OK]
test_isort3: [OK]
test_isort4: [OK]
test_is_sorted1: [OK]
test_is_sorted2: [OK]
test_is_sorted3: [OK]
test_is_sorted4: [OK]
QuickTests:
isort: [OK, passed 5000 tests]Properties Test Cases Total
Passed 1 10 11
Failed 0 0 0
Total 1 10 11Exception: ExitSuccess
"-a"でQuickChcekの実行回数を指定できます。"-j"はスレッド数の指定ができます。その他のオプションについてはmain ["--help"]などで見てください。
関連記事