stack测试

导入hspec依赖

配置package.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
name: projectname

dependencies:
- hspec

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

在package.yml定义的main文件添加ghc参数

  • -F:告诉 GHC 使用自定义的预处理器。
  • -pgmF hspec-discover:指定 hspec-discover 作为预处理器。

在Spec.hs添加ghc参数

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

编写测试

文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{-# LANGUAGE OverloadedStrings #-}

module ParserSpec (spec) where

import Test.Hspec
import Parser (parseLocalDate)
import Data.Time.Calendar (fromGregorian)
import Data.Time.LocalTime (LocalTime(..), TimeOfDay(..))

spec :: Spec
spec = do
parseLocalDateSpec

parseLocalDateSpec :: Spec
parseLocalDateSpec = describe "parseLocalDate" $ do
it "parses a valid date string" $ do
let dateStr = "2024-10-25 225530"
let expectedDate = LocalTime (fromGregorian 2024 10 25) (TimeOfDay 22 55 30)
parseLocalDate dateStr `shouldBe` expectedDate

it "returns Nothing for an invalid date string" $ do
let invalidDateStr = "invalid-date"
evaluate (parseLocalDate invalidDateStr) `shouldThrow` anyErrorCall
  • describe:用于分组相关的测试案例。一般用于描述被测试的函数或模块,通常是一级分组。
  • it:表示一个具体的测试案例,用于描述单个测试的行为或期望的结果。it 后面通常跟一个字符串描述该测试的目的。
  • shouldBe:断言运算符,用于验证测试的结果是否符合期望值。当表达式的结果与预期不符时,测试将失败。
  • evaluate:用于强制求值一个表达式,以便在需要测试的地方触发异常。通常与 shouldThrow 搭配使用。
  • shouldThrow:用于断言一个表达式是否抛出异常。与 evaluate 一起使用,检查表达式是否会因无效输入等原因引发错误。
  • anyErrorCall:一个通用匹配器,适用于 shouldThrow。当不关心异常的具体类型时可以使用 anyErrorCall 来匹配任何错误调用。

值得注意的是evaluate关键字在这里的应用,因为haskell的惰性求值的语言,也就是说下面这段代码将不会执行parseLocalDate invalidDateStr

1
parseLocalDate invalidDateStr `shouldThrow` anyErrorCall

因为parseLocalDate的结果并没有被其他方法使用,通过evaluate包裹才能强制执行该方法。