我有一个类型类Atomic,它定义了将某些类型转换为包装器值(/ Atom)的函数.我想定义一个QuickCheck属性,该属性指出:"对于所有实例Atomic,可以安全地存储和检索任何值".该属性如下所示:
class Atomic a where
toAtom :: a -> Atom
fromAtom :: Atom -> Maybe a
prop_AtomIdentity x = fromAtom (toAtom x) == Just x
Run Code Online (Sandbox Code Playgroud)
但是,如果我只是尝试通过QuickCheck运行该属性,它只需选择一个实例(Bool)并对其进行测试.我目前正在通过为测试列表中的每个受支持的原子类型定义类型签名来解决这个问题,但这很冗长且容易出错:
containerTests =
[ run (prop_AtomIdentity :: Bool -> Bool)
, run (prop_AtomIdentity :: Word8 -> Bool)
, run (prop_AtomIdentity :: String -> Bool)
{- etc -} ]
Run Code Online (Sandbox Code Playgroud)
我正在尝试定义一个自动执行此操作的函数:
forallAtoms :: (Atomic a, Show a) => (a -> Bool) -> [TestOptions -> IO TestResult]
forallAtoms x = …Run Code Online (Sandbox Code Playgroud) 我为一个函数编写了一个QuickCheck属性,该函数将两个已排序的输入合并为一个已排序的输出:
prop_merge xs ys =
if (sorted xs && sorted ys) then (sorted (merge xs ys)) else True
Run Code Online (Sandbox Code Playgroud)
也就是说,当输入被排序时,输出也被排序.它也可以写成:
prop_merge xs ys = not(sorted xs && sorted ys) || (sorted (merge xs ys))
Run Code Online (Sandbox Code Playgroud)
但我真的不喜欢这两个版本.QuickCheck中的"条件属性"有更好的语法吗?
我QuickCheck用来测试以下程序:
{-# LANGUAGE TemplateHaskell #-}
import Test.QuickCheck
import Test.QuickCheck.All
elementAt :: (Integral b) => [a] -> b -> a
elementAt [x] _ = x
elementAt (x:xs) 1 = x
elementAt (x:xs) b = elementAt xs (b - 1)
prop_elementAt xs b = length xs > 0 && b >= 0 && b < length xs ==> elementAt xs (b + 1) == xs !! b
main = $(quickCheckAll)
Run Code Online (Sandbox Code Playgroud)
虽然响应有所不同,但我不断收到消息
*** Gave up! Passed only x tests.
Run Code Online (Sandbox Code Playgroud)
这是我应该关注的吗?或者测试输入的性质是否决定了QuickCheck的运行时间?
我正在使用QuickCheck来测试自动生成的属性(类似于QuickSpec),但是我遇到的一个常见问题是耗尽内存,这可能是由于幼稚的递归生成器或非常大的函数输出(例如,一个失败是由指数引起的) Peano数的函数,会生成巨大的嵌套结构)。
我想知道是否有一种方法可以放弃评估(如果达到)(驻留)内存限制。似乎我们可以为超时执行此操作,但是内存似乎比较棘手。这样,如果我们使用过多的内存,则可以放弃该测试(就像==>先决条件失败了一样)。
通过查看weigh包的来源,我可以看到如何衡量整个程序的内存使用情况。这是可行的,但针对一个特定的表达式(也许通过获取一个线程使用的内存或其他东西)来衡量它会更好(更健壮)。
就我的目的而言,将表达式完全标准化就足够了,因为我不必担心递归结构(我可以将其应用于测试结果,实际上是布尔值)。
我正在使用QuickCheck 1,我有以下数据类型:
data A = ...
instance Arbitrary A where ...
data B = ...
instance Arbitrary B where ...
data C = C A B
Run Code Online (Sandbox Code Playgroud)
现在,我想定义一个Arbitrary实例C,使C值是使用现有的发电机产生A和B.我最终这样做了:
instance Arbitrary C where
arbitrary = elements [(C a b) |
a <- generate 20 (System.Random.mkStdGen 0) arbitrary,
b <- generate 20 (System.Random.mkStdGen 0) arbitrary]
Run Code Online (Sandbox Code Playgroud)
这是明确生成固定数量的值A和B必要的,还是有更好的方法将现有的结合Arbitraries到一个新的?
我正在尝试编写一个QuickCheck属性,它将一个或多个函数作为输入.为了简单起见,请考虑一个属性来检查函数组合是否等同于连续函数应用程序,以及一个快速而肮脏的测试驱动程序:
import Test.QuickCheck
prop_composition :: (Int -> Int) -> (Int -> Int) -> Int -> Bool
prop_composition f g x = (f . g) x == f (g x)
main :: IO ()
main = quickCheck prop_composition
Run Code Online (Sandbox Code Playgroud)
不幸的是,这不能编译,因为属性的输入需要实现,Show以便QuickCheck可以报告导致失败的输入,但是没有Show函数的实现:
Test.hs:10:7:
No instance for (Show (Int -> Int))
arising from a use of `quickCheck' at Test.hs:10:7-33
Possible fix: add an instance declaration for (Show (Int -> Int))
In the expression: quickCheck prop_composition
In the definition of …Run Code Online (Sandbox Code Playgroud) 是否有任何对HUnit或QuickCheck的扩展,允许像Bamboo这样的持续集成系统对测试结果进行详细报告?
到目前为止,我最好的想法是简单地将测试作为构建脚本的一部分进行触发,并依靠测试以非零退出代码进行失败.这对于在测试失败时获得注意力是有效的,但是将构建失败与测试失败混淆并且需要涉及通过控制台输出来确定问题的来源.
如果这是使用当前工具的最佳选择,我的想法是为HUnit编写一个报告模块,它将以JUnit XML格式生成输出,然后将CI工具指向它,就像报告Java项目一样.尽管如此,这看起来有些过时,所以我很感激您对现有选项和新开发方向的看法.
许多年前,一种名为Agitar的Java测试工具很受欢迎.它似乎做了类似基于财产的测试.
如今 - 基于Haskell Quickcheck的基于属性的测试很受欢迎.Java有许多端口,包括:
我的问题是:Agitar和Quickcheck基于属性的测试有什么区别?
从Doctest的自述文件中,可以使用带有QuickCheck的 doctest,如下所示:
-- |
-- prop> sort xs == (sort . sort) (xs :: [Int])
Run Code Online (Sandbox Code Playgroud)
我想用多行描述这个属性,可能就像
-- |
-- prop> sort xs ==
-- (sort . sort) (xs :: [Int])
Run Code Online (Sandbox Code Playgroud)
Doctest本身支持多行输入(同样来自自述文件)
-- |
-- >>> :{
-- let
-- x = 1
-- y = 2
-- in x + y + multiline
-- :}
-- 6
Run Code Online (Sandbox Code Playgroud)
我尝试了几种类似的语法,比如
-- |
-- prop> :{ sort xs ==
-- (sort . sort) (xs :: [Int])
-- }:
Run Code Online (Sandbox Code Playgroud)
没有任何成功.(在上面的示例中,错误消息是 parse …
我有一个我输入的协议:
data ProtocolPacket
= Packet1 Word8 Text Int8
| Packet2 Text
| Packet3 Int Text Text Text Text
| Packet4 Int Double Double Double Int16 Int16 Int16
...
deriving (Show,Eq)
Run Code Online (Sandbox Code Playgroud)
另外,我已经为每个数据包实现了序列化/反序列化代码.当然,我想在Quickcheck中测试这个协议,并确保对任何输入组合的任何数据包进行序列化和反序列化都会让我准确地回复我所放入的内容.所以我继续为Arbitrary类型类实现这些数据包,如下所示:
instance Arbitrary ProtocolPacket where
arbitrary = do
packetID <- choose (0x00,...) :: Gen Word8
case packetID of
0x00 -> do
a <- arbitrary
b <- arbitrary
c <- arbitrary
return $ Packet1 a b c
0x01 -> do
a <- arbitrary
return $ Packet2 a
0x02 -> …Run Code Online (Sandbox Code Playgroud)