Sunday, 8 September 2013

What is better approach to testing pure functions?

What is better approach to testing pure functions?

I'm new to Haskell. I'm testing a simple function with 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
]
]
What bothers me is that it's recommended to test pure functions with
QuickCheck properties and impure functions with HUnit test cases. But that
way, I would have to just repeat the function definition for each of 3
cases (Const, Variable and Polymorphic) in properties to test that the
function returns what it's supposed to. That is too much duplication in my
opinion:
prop_ValueVariable quantity Variable =
calculate quantity Variable
== ((**2) . fromIntegral $ quantity)
(and so on for all the cases of Kind)
In contrast, in the current code I test only one "obvious" property of
function and provide some "sample points" for what the function should
return, without actually duplicating the definition (in spirit of unit
testing).
What is right approach?
Use properties for testing of all aspects of this function and possibly
duplicate its definition in tests
Use properties only for, well, "properties" of what should be returned,
but don't duplicate the definition and provide just some unit tests

No comments:

Post a Comment