Unit testing 测试纯函数的更好方法是什么?
我是哈斯克尔的新手。我正在用Unit testing 测试纯函数的更好方法是什么?,unit-testing,testing,haskell,Unit Testing,Testing,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
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
]
]
(对于种类的所有情况,依此类推
)
相反,在当前代码中,我只测试函数的一个“明显”属性,并为函数应该返回的内容提供一些“样本点”,而不实际复制定义(本着单元测试的精神)
什么是正确的方法
不,当然你不应该以这种方式复制定义。重点是什么?您还可以将测试简化为
prop_琐碎的qk=calculateqk==calculateqk
。唯一的情况是,当你计划改变方法时,在将来计算函数,并检查它仍然返回相同的结果。
但是,如果您的单元测试是通过将值放入函数定义并查看结果来创建的,那么出于同样的原因,它们也不是特别有用。基于属性的测试适用于纯代码,而针对非纯代码的单元测试是有用的指南,但不是绝对真理。单元测试对于纯代码也很有用。我通常从单元测试开始,例如
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
我并没有“计划”去改变它的计算方式,但是当你重构代码并且有某种bug潜入时,测试的目的不是为了打破吗?我也不太明白你第二段的意思。那么什么测试是有用的?定义测试的语法是什么?找不到
descripe
函数的说明(原文如此!)
describe "loadUser" $ do
it "retrieves saved users from the database" $ do
property $ \user -> do
saveUser user >>= loadUser `shouldReturn` user