hspecでHaskellのテストコードを書く (Haskell初心者が電卓アプリを作る : 4)

Haskell で電卓アプリを作った際のテストコードの書き方を紹介します。この記事は連載記事「Haskell初心者が電卓アプリを作る」の4回目の記事です。

ソースコードは以下にアップしています。

https://github.com/daikon-oroshi/haskell-calculator-sample

準備

package.yaml の test の dependencies に hspec を追加します。

...

tests:
  calculator-test:
    main:                Spec.hs
    source-dirs:         test
    ghc-options:
    - -threaded
    - -rtsopts
    - -with-rtsopts=-N
    dependencies:
    - calculator
    - hspec

次に test/Spec.hs に 1 行だけ記載します。

{-# OPTIONS_GHC -F -pgmF hspec-discover #-}

テストコードの書き方

ファイル名を xxxSpec.hs とします。今回は ExpNotation をテストするので ExpNotationSpec.hs という名前にします。以下の様に spec という関数を定義し spec を export します。

module ExpNotationSpec (spec) where

import Test.Hspec ( describe, it, shouldBe, Spec, Expectation )

spec :: Spec
spec = do
  describe "表示(display)のテスト" $ do
    it "1の表示" $
      display unitDispVal `shouldBe` "1"
    it "-1の表示" $
      display (unitDispVal {_significand = -1}) `shouldBe` "-1"

  describe "addDigitのテスト" $ do
    it "0に追加" $
      display (addDigit zeroDispVal 3) `shouldBe` "3"
    it "1に1を追加" $
      display (addDigit unitDispVal 1) `shouldBe` "11"

以下の様に書くこともできます。

module ExpNotationSpec (spec) where

import Test.Hspec ( describe, it, shouldBe, Spec, Expectation )

testDisplay :: ExpNotation -> String -> Expectation
testDisplay val _exp = display val `shouldBe` _exp

testAddDigit :: (ExpNotation, Int) -> String -> Expectation
testAddDigit (dv, num) _epx = display (addDigit dv num) `shouldBe` _epx

tests :: [(String, [(String, Expectation)])]
tests = [
        ("表示(display)のテスト", [
            ("1の表示", testDisplay unitDispVal "1")
            , ("-1の表示", testDisplay (unitDispVal {_significand = -1}) "-1"
        ])
        , ("addDigitのテスト",[
            ("0に追加", testAddDigit (zeroDispVal, 3) "3")
            , ("1に1を追加", testAddDigit (unitDispVal, 1) "11")
        ] )
    ]


spec :: Spec
spec = do
    mapM_ (\(n, p) ->
            describe n $ do
                mapM_ (uncurry it) p
        ) tests

実行

テストファイル名を xxxSpec.hs という名前で作成し、

stack test

または

stack build --test

を実行すると、test/ 以下のファイルが全て実行されます。

実行結果

実行結果は以下のように出力されます。

ExpNotation
  表示(display)のテスト
    1の表示 [✔]
    -1の表示 [✔]
    0. の表示 [✔]
    0.00 の表示 [✔]
    91. の表示 [✔]
    9.1 の表示 [✘]
    -91. の表示 [✔]
  addDigitのテスト
    0に追加 [✔]
    1に1を追加 [✔]
  掛け算のテスト
    5 * 9 [✔]
  足し算のテスト
    0と1の足し算 [✔]
MExpNotation
  表示(display)のテスト
    Nothing [✔]
    1 [✔]
  addDigitのテスト
    Nothingに追加 [✔]
    1に追加 [✔]
  掛け算のテスト
    5 * 9 [✔]
    5 * Nothin [✔]
    Nothing * 9 [✔]
    Nothing * Nothing [✔]
  足し算のテスト
    0と1の足し算 [✔]
    Nothing + 1 [✔]
    0 + Nothing [✔]
    Nothing + Nothing [✔]
  割り算のテスト
    1 / 2 [✔]
    1 / 0 [✔]
    Nothing / 2 [✔]
    1 / Nothing [✔]
    Nothing / Nothing [✔]

Failures:

  test/ExpNotationSpec.hs:22:36:
  1) ExpNotation.表示(display)のテスト 9.1 の表示
       expected: "9.11"
        but got: "9.1"

  To rerun use: --match "/ExpNotation/表示(display)のテスト/9.1 の表示/"

Randomized with seed 1499174619

Finished in 0.0078 seconds
47 examples, 1 failure