I was wondering if there was a known pattern for writing generic unit test code whose purpose it is to check (as a black box) the various instance (implementation of) a type class. For example:
import Test.HUnit
class M a where
foo :: a -> String
cons :: Int -> a -- some constructor
data A = A Int
data B = B Int
instance M A where
foo _ = "foo"
cons = A
instance M B where
foo _ = "bar" -- implementation error
cons = B
I would like to write a function tests
returning a Test
with some way of specifying to tests
the particular instance to which the code applies. I was thinking adding tests
to the definition of the class with a default implementation (ignoring the coupling issue between testing code and actual code for now), but I can't simply have tests :: Test
, and even if I try tests:: a -> Test
(so having to artificially pass a concrete element of the given type to call the function), I cannot figure out how to refer to cons
and foo
inside the code (type annotations like (cons 0) :: a
won't do).
Assuming I have class (Eq a) => M a where ...
instead, with types A
and B
deriving Eq
, I could trick the compiler with something like (added to the definition of M
):
tests :: a -> Test
tests x = let
y = (cons 0)
z = (x == y) -- compiler now knows y :: a
in
TestCase (assertEqual "foo" (foo y) "foo")
main = do
runTestTT $ TestList
[ tests (A 0)
, tests (B 0)
]
But this is all very ugly to me. Any suggestion is warmly welcome