I am new to Haskell. I am testing a simple function using 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 ] ]
My concern is that he recommended testing pure functions with QuickCheck
properties and unclean functions with HUnit
test HUnit
. But in this case, I will just need to repeat the definition of the function for each of the three cases ( Const
, Variable
and Polymorphic
) in the properties to check whether the function returns what it should have. Too much duplication, in my opinion:
prop_ValueVariable quantity Variable = calculate quantity Variable == ((**2) . fromIntegral $ quantity)
(etc. for all cases of Kind
)
In contrast, in the current code I test only one “obvious” property of a function and provide some “sampling points” for what the function should return, without actually duplicating the definition (in the spirit of unit testing).
What is the right approach?
- Use properties to test all aspects of this function and possibly duplicate its definition in tests
- Use properties only for, well, the “properties” of what should be returned, but not duplicate the definition and provide only some unit tests
source share