首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在QuickCheck中运行特定数量的测试?

如何在QuickCheck中运行特定数量的测试?
EN

Stack Overflow用户
提问于 2019-06-11 17:12:42
回答 1查看 586关注 0票数 0

我正在努力学习Haskell,特别是QuickCheck。虽然Haskell网上有很多信息,但我很难用QuickCheck创建一些随机测试。

例如,我有以下脚本:

代码语言:javascript
复制
import Test.QuickCheck

whatAge :: Int -> Int -> Int -> Int -> Bool

whatAge age1 age2 age3 age4
  | age1 + age2 + age3 + age4 == 5 = True
  | otherwise = False

main = do
    verboseCheck  whatAge

当我运行它显示:

代码语言:javascript
复制
*** Failed! Falsifiable (after 1 test): 
0
0
0
0

这就足够了,它显示了一个函数为假的测试。

不过,我想做的是:

  1. 即使在失败时也生成200个随机测试(即,a即使whatAge函数的输出为假)
  2. 能够在我的函数参数上设置一个范围,例如: x1范围从1到30 x2范围从1到40 x3范围从1到50 x4范围从1到60
  3. 能够生成不重复的测试。

根据我的理解,nr3在QuickCheck中是不可能的,因为我必须使用smallCheck,但我不确定第1点和第2点。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-06-11 18:32:04

对于输入的简单属性,可以使用捕获它们的适当Arbitrary实例创建newtype。所以:

代码语言:javascript
复制
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

import Data.Proxy
import GHC.TypeLits
import Test.QuickCheck

newtype Range (m :: Nat) (n :: Nat) a = Range { getVal :: a }
    deriving (Eq, Ord, Read, Show, Num, Real, Enum, Integral)

numVal :: forall n a. (KnownNat n, Num a) => a
numVal = fromInteger (natVal @n Proxy)

instance (KnownNat m, KnownNat n, Arbitrary a, Integral a) => Arbitrary (Range m n a) where
    arbitrary = fromInteger <$> choose (numVal @m, numVal @n)
    shrink hi = go (numVal @m) where
        go lo | lo == hi = [] | otherwise = lo : go ((lo+hi+1)`div`2) -- overflow? what's that? lmao

whatAge :: Range 1 30 Int -> Range 1 40 Int -> Range 1 50 Int -> Range 1 60 Int -> Bool
whatAge (Range age1) (Range age2) (Range age3) (Range age4)
    = age1 + age2 + age3 + age4 == 5

在ghci:

代码语言:javascript
复制
> verboseCheck whatAge
Failed:  
Range {getVal = 17}
Range {getVal = 29}
Range {getVal = 3}
Range {getVal = 16}

Failed:                                  
Range {getVal = 1}
Range {getVal = 29}
Range {getVal = 3}
Range {getVal = 16}

Failed:                                               
Range {getVal = 1}
Range {getVal = 1}
Range {getVal = 3}
Range {getVal = 16}

Failed:                                                
Range {getVal = 1}
Range {getVal = 1}
Range {getVal = 1}
Range {getVal = 16}

Failed:                                                
Range {getVal = 1}
Range {getVal = 1}
Range {getVal = 1}
Range {getVal = 1}

*** Failed! Falsifiable (after 1 test and 4 shrinks):  
Range {getVal = 1}
Range {getVal = 1}
Range {getVal = 1}
Range {getVal = 1}

对于更复杂的属性,不清楚如何直接创建满足属性的随机值,可以使用QuickCheck的(==>)操作符。例如,对于如上所述的范围检查:

代码语言:javascript
复制
> verboseCheck (\x -> (1 <= x && x <= 30) ==> x*2 < 60)
Skipped (precondition false):
0

Passed:                
1

*** Failed! Falsifiable (after 33 tests):                  
30

要进行确切的200个测试,您可以调用quickCheckWith进行一次测试,每次200次;或者可以通过手动调用arbitrary上的属性直接进行generate测试结果。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56548719

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档