使用Haskell的Quickcheck进行传递性的最佳测试

时间:2018-06-17 17:37:57

标签: haskell testing

在下面的三个测试中,这是对传递性的最佳测试。这来自我的previous question。通常的传递性逻辑规则(R(a,b)和R(b,c))=> R(a,c)似乎不适用于这种情况。因此,我认为prop_trans3不是一个好的测试,因为这三个术语中的每一个代表不同的堆栈。 但prop_trans1prop_trans2中哪一个最适合测试传递性?

import Test.QuickCheck
data Block = Block Int deriving (Show,Eq)
-- MoveOnto(bl,b2,s) is read as b2 is moved into and onto bl on stack or table.
data Stack = EmptyTable  |  MoveOnto Block Block Stack deriving  (Show,Eq) 
isOn :: Block -> Block -> Stack -> Bool
isOn b1 b2 (MoveOnto b3 b4 s) |  ((b1 == b3) && (b4 == b2)) || (isOn b4 b2 s)   =  True
isOn _ _ _  = False

instance Arbitrary (Block) where
  arbitrary = fmap Block arbitrary

instance Arbitrary (Stack) where
  arbitrary = oneof [return EmptyTable, MoveOnto <$> arbitrary <*> arbitrary <*> arbitrary]

prop_trans1 b1 b2 s      =  isOn b1 b2 (MoveOnto b1 b2 s)
prop_trans2 b1 b2 b3 s   =  isOn b3 b1 (MoveOnto b3 b2 (MoveOnto b2 b1 s))
prop_trans3 b1 b2 b3 s   =  ((isOn b2 b1 (MoveOnto b2 b1 s)) && (isOn b3 b2 (MoveOnto b3 b2 s))) <=  (isOn b3 b1 (MoveOnto b3 b1 s))

1 个答案:

答案 0 :(得分:1)

我认为即使在这种情况下,传统的通常定义也适用。

prop_trans a b c s = (r a b && r b c) ==> r a c
    where r x y = isOn x y s

不幸的是,检查此属性会导致很多的丢弃。只需从a中显示的块中提取bcs,您就可以做得更好:

listBlocks (MoveOnto b1 b2 s) = b1:b2:listBlocks s
listBlocks EmptyTable = []

prop_trans2 s = do
    [a,b,c] <- replicateM 3 . elements . listBlocks $ s
    return (prop_trans a b c s)

有可能做得更好,但似乎没有必要,因为这让我很快得到一个反例:

> quickCheckWith stdArgs { maxDiscardRatio = 1000 } prop_trans2
*** Failed! Falsifiable (after 6 tests):  
MoveOnto (Block 4) (Block (-2)) (MoveOnto (Block (-2)) (Block 4) (MoveOnto (Block 2) (Block 5) EmptyTable))