Haskell 美味的单元测试 - 如何使用组和简单的固定装置来避免重复?

Haskell Tasty Unit Tests - how to use groups and simple fixtures to avoid repetition?

您将如何编写一个 Tasty HUnit 测试,在单个测试中包含针对单个夹具变量的多项检查,或者至少是一组整齐的此类测试?

例如,考虑这个 Gherkin 规范:

Scenario: A 3-Vector has x, y and z components
  Given: a <- Vec(1.0, 2.0, 3.0)
  Then: a.x = 1.0
  And a.y = 2.0
  And a.z = 3.0

我可以做这样的事情,但它非常重复:

unitTests = testGroup "All Unit Tests"
  [ testCase "A 3-Vector has x, y and z components" $ assertEqual [] (x $ Vec 1.0 2.0 3.0) 1.0
  , testCase "A 3-Vector has x, y and z components" $ assertEqual [] (y $ Vec 1.0 2.0 3.0) 2.0
  , testCase "A 3-Vector has x, y and z components" $ assertEqual [] (z $ Vec 1.0 2.0 3.0) 3.0
  ]

我担心的是我重复了三次场景名称,并且我也创建了三次夹具。我想找到一种方法将所有三个断言分组到一个标题为 "A 3-Vector has x, y and z components" 的组中,并且只指定一次夹具 Vec。

我可以扩展测试规范以尽量减少一些重复描述,但如果可以的话,我宁愿坚持 Gherkin 规范:

unitTests = testGroup "All Unit Tests"
  [ testCase "A 3-Vector has x component" $ assertEqual [] (x $ Vec 1.0 2.0 3.0) 1.0
  , testCase "A 3-Vector has y component" $ assertEqual [] (y $ Vec 1.0 2.0 3.0) 2.0
  , testCase "A 3-Vector has z component" $ assertEqual [] (z $ Vec 1.0 2.0 3.0) 3.0
  ]

我不知道有什么方法可以只为组定义一次 Vec。

我想做的是这样的(不是真正的代码!):

unitTests = testGroup "All Unit Tests"
  [ testScenario "A 3-Vector has x, y and z components" 
    let v = Vec 1.0 2.0 3.0 in
    [ testCase "x" assertEqual [] (x $ v) 1.0
    , testCase "y" assertEqual [] (y $ v) 2.0
    , testCase "z" assertEqual [] (z $ v) 3.0
    ]
  ]

感谢 ,他建议我的 "not real code" 并没有太离谱。他是对的。

经过一些调整,我最终得到了这个,它按我想要的方式工作:

data Vec = Vec { x, y, z :: Double } deriving (Show)

unitTests = testGroup "All Unit Tests"
  [ testGroup "A 3-Vector has x, y and z components" $
    let v = Vec 1.0 2.0 3.0 in
    [ testCase "x" $ assertEqual [] (x v) 1.0
    , testCase "y" $ assertEqual [] (y v) 2.0
    , testCase "z" $ assertEqual [] (z v) 3.0
    ]
  ]

在一个测试用例中有多个断言是完全没问题的。所以你可以这样做:

unitTests = testGroup "All Unit Tests"
  [ testCase "A 3-Vector has x, y and z components" $ do
    let v = Vec 1.0 2.0 3.0
    assertEqual [] (x v) 1.0
    assertEqual [] (y v) 2.0
    assertEqual [] (z v) 3.0
  ]