Мне было интересно, существует ли известный шаблон для написания универсального кода модульного тестирования, целью которого является проверка (как черный ящик) различных экземпляров (реализации) класса типов. Например:
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
Я хотел бы написать функцию, tests
возвращающую Test
, с каким-то способом указать tests
конкретный экземпляр, к которому применяется код. Я думал добавить tests
к определению класса с реализацией по умолчанию (пока игнорируя проблему связи между тестируемым кодом и фактическим кодом), но я не могу просто иметь tests :: Test
, и даже если я попробую tests:: a -> Test
(поэтому придется искусственно передать конкретный элемент данного типа для вызова функции), я не могу понять, как ссылаться на cons
и foo
внутри кода (аннотации типов, такие как (cons 0) :: a
, не годятся).
Предполагая, что вместо этого у меня есть class (Eq a) => M a where ...
, с типами A
и B
, производными от Eq
, я мог бы обмануть компилятор чем-то вроде (добавлено к определению 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)
]
Но мне все это очень некрасиво. Любое предложение тепло приветствуется