下面的数据结构可以用后面的 Tasty-SmallCheck 相关代码进行测试。有一个与构造函数 ShB 必须保持的关系:第二个和第三个正整数最多应该和第一个一样大。
data Shape = ShA Int Int Bool
| ShB Int Int Int Bool Bool
deriving (Show,Read,Eq)
构造函数 ShaA 应该具有正 Int,否则参数之间没有关系。
auxShA :: (Positive Int, Positive Int, Bool) -> Shape
auxShA (i,j,b) = ShA (fromIntegral i) (fromIntegral j) b
auxShB :: (Positive Int, Positive Int, Positive Int) -> Bool -> Bool -> Shape
auxShB (a1,a2,a3) = ShB i u d
where
(i,u,d) = auxTriplet (a1,a2,a3)
auxTriplet :: (Positive Int, Positive Int, Positive Int) -> (Int,Int,Int)
auxTriplet (a,b,c)
| a >= b && a >= c = (fromIntegral a, fromIntegral b, fromIntegral c)
| b >= a && b >= c = (fromIntegral b, fromIntegral a, fromIntegral c)
| otherwise = (fromIntegral c, fromIntegral a, fromIntegral b)
consB :: (Serial m a1, Serial m a2, Serial m a3, Serial m b, Serial m c) =>
((a1,a2,a3) -> b -> c -> e) -> Series m e
consB f = decDepth $
f <$> series
<~> series
<~> series
instance Monad m => Serial m Shape where
series = cons1 auxShA \/ consB auxShB
生成的案例还可以,但是可以看到重复的案例,例如
list 4 series :: [Shape]
问题是,当满足以下条件时,如何使用 SmallCheck (tasty) 生成测试用例?
- 有些属性必须保持,例如第一个参数必须为正
- 如果第一个参数应该大于 10::Int 怎么办?
- 继续,如果第二个参数应该在第一个 - 5 和第一个之间,而第三个应该在第二个 - 5 和第二个之间呢?
或者,如何生成动态依赖于先前生成的值的测试用例?
第一个想法是向 Shape 编写构造函数来检查输入是否有效(例如上面的要点),但是这种方法仍然存在重复测试用例生成的问题。
上面的代码使用了与SmallCheck invariant -answer类似的解决方案 。