我正在尝试开始使用 Haskell 的 QuickCheck,虽然我熟悉测试方法背后的概念,但这是我第一次尝试将它用于超越测试之类的项目的项目reverse . reverse == id
中事物。我想知道将它应用于业务逻辑是否有用(我认为很有可能)。
因此,我想测试的几个现有业务逻辑类型函数如下所示:
shouldDiscountProduct :: User -> Product -> Bool
shouldDiscountProduct user product =
if M.isNothing (userDiscountCode user)
then False
else if (productDiscount product) then True
else False
对于这个函数,我可以编写一个 QuickCheck 规范,如下所示:
data ShouldDiscountProductParams
= ShouldDiscountProductParams User Product
instance Show ShouldDiscountProductParams where
show (ShouldDiscountProductParams u p) =
"ShouldDiscountProductParams:\n\n" <>
"- " <> show u <> "\n\n" <>
"- " <> show p
instance Arbitrary ShouldDiscountProductParams where
arbitrary = ShouldDiscountProductParams <$> arbitrary <*> arbitrary
shouldDiscountProduct :: Spec
shouldDiscountProduct = it behavior (property verify)
where
behavior =
"when product elegible for discount\n"
<> " and user has discount code"
verify (ShouldDiscountProductParams p t) =
subject p t `shouldBe` expectation p t
subject =
SUT.shouldDiscountProduct
expectation User{..} Product{..} =
case (userDiscountCode, productDiscount) of
(Just _, Just _) -> True
_ -> False
我最终得到的是一个更优雅地expectation
验证当前实现的函数。shouldDiscountProduct
所以现在我有一个测试,我可以重构我原来的功能。但我的自然倾向是将其更改为以下实现expectation
:
shouldDiscountProduct User{..} Product{..} =
case (userDiscountCode, productDiscount) of
(Just _, Just _) -> True
_ -> False
但这很好,对吧?如果将来我想再次更改此功能,我已经准备好相同的功能来验证我的更改是否合适并且不会无意中破坏某些东西。
或者这是矫枉过正/双重簿记?我想我已经从 OOP 测试中根深蒂固地告诉我,你应该尽量避免镜像实现细节,这实际上不能比这更进一步,它就是实现!
然后我想当我完成我的项目并添加这些类型的测试时,我将有效地添加这些测试,然后重构为我在expectation
断言中实现的更清晰的实现。显然,对于比这些更复杂的功能,情况并非如此,但我认为在这一轮中会如此。
人们对使用基于属性的业务逻辑类型功能的测试有什么经验?这种事情有什么好的资源吗?我想我只是想验证我是否以适当的方式使用 QC,而这只是我的 OOP 过去让我对此产生怀疑......