Я пытаюсь начать работу с 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
Но это нормально, верно? Если я захочу снова изменить эту функцию в будущем, у меня есть та же функция, готовая проверить, что мои изменения уместны и не нарушают что-то непреднамеренно.
Или это перебор/двойная бухгалтерия? Я полагаю, что из ООП-тестирования я усвоил, что вы должны стараться избегать зеркалирования деталей реализации, насколько это возможно, это буквально не может быть дальше этого, это реализация!
Затем я думаю, что по мере того, как я прохожу свой проект и добавляю такие тесты, я фактически собираюсь добавлять эти тесты, а затем рефакторинг для более чистой реализации, которую я реализую в утверждении expectation
. Очевидно, что это не будет иметь место для более сложных функций, чем эти, но в раунде, я думаю, будет иметь место.
Каков опыт использования тестирования на основе свойств для функций бизнес-логики? Есть ли хорошие ресурсы для такого рода вещей? Я думаю, я просто хочу убедиться, что я использую QC надлежащим образом, и это просто мое прошлое ООП вызывает у меня сомнения по этому поводу...