gpt4 book ai didi

unit-testing - 什么是测试纯函数的更好方法?

转载 作者:行者123 更新时间:2023-11-28 19:53:15 26 4
gpt4 key购买 nike

我是 Haskell 的新手。我正在使用 Test.Framework 测试一个简单的函数:

import Test.Framework (defaultMain, testGroup)
import Test.Framework.Providers.HUnit
import Test.Framework.Providers.QuickCheck2 (testProperty)

import Test.QuickCheck
import Test.HUnit

data Kind = Variable
| Const
| Polymorphic
deriving (Show, Eq, Ord)

calculate :: Int -> Kind -> Float

calculate quantity Variable =
(**2) . fromIntegral $ quantity

calculate _ Const =
10

calculate quantity Polymorphic =
if quantity <= 10 then
10
else
(**2) . fromIntegral $ quantity

prop_ValuePositive quantity kind =
calculate quantity kind
>= 0.0

test_ValueVariable1 =
calculate 1 Variable
@?= (**2) 1

test_ValueVariable2 =
calculate 10 Variable
@?= (**2) 10

test_ValueConst1 =
calculate 1 Const
@?= 10

test_ValueConst2 =
calculate 10 Const
@?= 10

test_ValuePolymorphic1 =
calculate 1 Polymorphic
@?= 10

test_ValuePolymorphic2 =
calculate 11 Polymorphic
@?= (**2) 11

instance Test.QuickCheck.Arbitrary Kind where
arbitrary = Test.QuickCheck.oneof(
[return Variable,
return Const,
return Polymorphic])

main = defaultMain tests

tests = [
testGroup "Value" [
testProperty "Value is positive" prop_ValuePositive,
testCase "Value is calculated right for Variable"
test_ValueVariable1,
testCase "Value is calculated right for Variable"
test_ValueVariable2,
testCase "Value is calculated right for Const"
test_ValueConst1,
testCase "Value is calculated right for Const"
test_ValueConst2,
testCase "Value is calculated right for Polymorphic"
test_ValuePolymorphic1,
testCase "Value is calculated right for Polymorphic"
test_ValuePolymorphic2
]
]

令我困扰的是,建议使用 QuickCheck 属性测试纯函数,使用 HUnit 测试用例测试非纯函数。但那样的话,我将不得不为属性中的 3 种情况(ConstVariablePolymorphic)中的每一种重复函数定义以进行测试该函数返回它应该返回的内容。在我看来,这是太多的重复:

prop_ValueVariable quantity Variable =
calculate quantity Variable
== ((**2) . fromIntegral $ quantity)

(对于 Kind 的所有情况依此类推)

相比之下,在当前代码中,我只测试了函数的一个“明显”属性,并为函数应返回的内容提供了一些“样本点”,而没有实际复制定义(本着单元测试的精神)。

什么是正确的做法?

  1. 使用属性测试此功能的所有方面,并可能在测试中复制其定义
  2. 仅将属性用于应该返回的“属性”,但不要重复定义并仅提供一些单元测试

最佳答案

基于属性的测试适用于纯代码,单元测试适用于不纯代码,这是一个有用的指导方针,但不是绝对真理。单元测试对于纯代码也很有用。我通常从单元测试开始,例如

describe "parseMarkdown" $ do
it "parses links" $ do
parseMarkdown "[foo](http://foo.com/)" `shouldBe` Link "http://foo.com" "foo"

然后将其抽象为一个属性

  it "parses *arbitrary* links" $
property $ \link@(Link url name) ->
parseMarkdown "[" ++ name ++ "](" ++ url ++ ")" `shouldBe` link

但有时我只是坚持单元测试,因为要么 (a) 没有好的属性,要么 (b) 属性不会增加测试覆盖率。

另一方面,属性对于非纯代码也很有用。你例如可能想用属性测试你的数据库抽象

describe "loadUser" $ do
it "retrieves saved users from the database" $ do
property $ \user -> do
saveUser user >>= loadUser `shouldReturn` user

关于unit-testing - 什么是测试纯函数的更好方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18683362/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com