﻿ 单元测试 – 单元测试功能数据结构的多个实现,无需代码重复 - 代码日志

#### 单元测试 – 单元测试功能数据结构的多个实现,无需代码重复

``````data SimpleQueue a = SimpleQueue [a]
data FancyQueue a = FancyQueue ([a], [a])

class Queue q where
empty :: q a
enqueue :: a -> q a -> q a
dequeue :: q a -> (a, q a)

instance Queue SimpleQueue where
empty = SimpleQueue []
enqueue e (SimpleQueue xs) = SimpleQueue \$xs ++ [e]
dequeue (SimpleQueue (x:xs)) = (x, SimpleQueue xs)

instance Queue FancyQueue where
empty = FancyQueue ([], [])
enqueue e (FancyQueue (h, t)) =
if length h > length t
then FancyQueue (h, e:t)
else FancyQueue (h ++ reverse (e:t), [])
dequeue (FancyQueue ((e:h), t)) =
if length h > length t
then (e, FancyQueue (h, t))
else (e, FancyQueue (h ++ reverse t, []))
``````

``````f :: (Queue q, Num a) => q a -> (a, q a)
f = dequeue . enqueue 4

makeTest = let (a, _) = f (empty :: SimpleQueue Int)
(b, _) = f (empty :: FancyQueue Int)
in assertEqual "enqueue, then dequeue" a b

test1 = makeTest

main = runTestTT (TestCase test1)
``````

``````makeTest t = let (a, _) = t (empty :: SimpleQueue Int)
(b, _) = t (empty :: FancyQueue Int)
in assertEqual "enqueue, then dequeue" a b

test1 = makeTest f

main = runTestTT (TestCase test1)
``````

``````queue.hs:52:30:
Couldn't match expected type `FancyQueue Int'
with actual type `SimpleQueue Int'
In the first argument of `t', namely `(empty :: SimpleQueue Int)'
In the expression: t (empty :: SimpleQueue Int)
In a pattern binding: (a, _) = t (empty :: SimpleQueue Int)
``````

``````{-# LANGUAGE RankNTypes #-}

import Test.HUnit

import Queue
import SimpleQueue
import FancyQueue

makeTest :: String -> (forall q a. (Num a, Queue q) => q a -> (a, q a)) -> Assertion
makeTest msg t = let (a, _) = t (empty :: SimpleQueue Int)
(b, _) = t (empty :: FancyQueue Int)
in assertEqual msg a b

test1 = makeTest "enqueue, then dequeue" \$dequeue . enqueue 4
test2 = makeTest "enqueue twice, then dequeue" \$dequeue . enqueue 9 . enqueue 4
test3 = makeTest "enqueue twice, then dequeue twice" \$dequeue . snd . dequeue . enqueue 9 . enqueue 4

tests = TestList \$map (\ test -> TestCase test) [test1, test2, test3]

main = runTestTT tests
``````

``````makeTest :: (forall q a. (Num a, Queue q) => q a -> (a, q a)) -> Assertion
makeTest t = let (a, _) = t (empty :: SimpleQueue Int)
(b, _) = t (empty :: FancyQueue Int)
in assertEqual "enqueue, then dequeue" a b
``````

``````{-# LANGUAGE RankNTypes #-}
``````

``````foo :: Show a => a -> b -> c
``````

``````foo :: forall a b c. Show a => a -> b -> c
``````