【问题标题】:Haskell quickcheck - how to generate only printable stringsHaskell quickcheck - 如何只生成可打印的字符串
【发布时间】:2014-01-05 14:07:43
【问题描述】:

我有一组对字符串进行编码/解码的简单演示程序,并希望为它们生成一些 quickCheck 测试,但将测试限制为仅可打印的字符串。由于生成和拒绝的测试用例过多,使用警卫太慢并且失败,所以我想为这个域创建一个安全的生成器。

我所看到的对此的引用说 (1) 为 Char 定义自己的 Arbitrary 实例并使用它仅生成字符串的可打印字符,或者(2) 必须将函数本身包装在 newtype 中并为此编写一个 Arbitrary 实例。

但是尝试执行 (1) 它失败了,因为现在在 Test.QuickCheck 中有一个对此的定义,那么如何做到这一点 - 为新类型创建一个 safeChar 生成器,然后再次必须生产一个适配器来测试功能? (关于此的 RWH 书籍部分指出,推荐此 DIY Char 定义已过时。)

尝试执行 (2) 似乎我可以为测试命题添加一个本地化且简单(但失败)的保护,或者编写一个新的包装器和相关的生成器,这似乎更混乱。

显然这很简单(!)并且提供了所有工具,但是有人可以建议这是否是正确的分析,并举例说明如何最好地做到这一点?

【问题讨论】:

  • 好问题,我不想贬低它,我可以看到您可能期望从有效和无效数据中得到不同类型的输出,但同时检查可能不是一个好主意即使给定不可打印的字符串,您的库也会按预期执行?例如,可以想象,在未来的某个时候,有人会在 Web 服务中使用您的代码,而对令人惊讶的数据的行为可能是攻击媒介。
  • 好点 - 但这不是“真实世界”,而是更多的快速检查学习练习 - 仍在进行中!
  • 这里的问题不在于单个值的生成器,而是在复杂/嵌套数据结构上自定义生成器。

标签: haskell quickcheck


【解决方案1】:

起点肯定是genSafeChar 生成器,它的类型可以是Gen Char。例如:

genSafeChar :: Gen Char
genSafeChar = elements ['a'..'z']

然后您可以将其构建到 genSafeString 生成器中,例如listOf:

genSafeString :: Gen String
genSafeString = listOf genSafeChar

此时您有几个合理的选择。为String 制作一个newtype 包装器:

newtype SafeString = SafeString { unwrapSafeString :: String }
    deriving Show

instance Arbitrary SafeString where
    arbitrary = SafeString <$> genSafeString

(在这种情况下,您可能只是内联genSafeString 的定义)

然后你可以像这样使用它:

testWibble (SafeString str) = str == str

或者,您可以在需要安全字符串的每个点使用forAll

testWibble = forAll genSafeString $ \str -> str == str

【讨论】:

  • 确实需要一个 Lorem Ipsum QuickCheck 生成器。这个问题反复出现。
  • @Ganesh - 谢谢 - forAll 工作正常。但尝试其他我得到:***失败!异常:'没有默认生成器'(1次测试后):SafeString {unWrap =“生成器抛出的异常:'没有默认生成器'。我可以使用类似的东西更简单地构建这个生成器:任意= FN {unFN = listOf $元素 ['a'..'z'] } .
  • 是的,你绝对可以按照你的建议内联东西——我只是更明确地帮助展示这些部分是如何构建的。我看不出你是如何得到你引用的错误的。会发生某种类型的 instance Arbitrary Foo 没有实现 arbitrary 并且您尝试在该类型上调用 arbitrary,因为该方法有一个默认实现,它只会引发错误,但在上面的代码中我看不出怎么会这样。可以分享一下代码吗?
  • 您可以以正常方式为您的测试提供不需要自定义生成器的参数,例如testWibble int = forAll genSafeString $ \str -&gt; ...int...str
  • 第 145 行是你的问题 - 它没有缩进,所以你有一个没有子句的 instance Arbitrary AlphaString where 定义,然后是你自己的顶级 arbitrary 值的新定义这不是 QuickCheck 的。
【解决方案2】:

目前QuickCheck 有一个PrintableString 类型,它也有一个arbitrary 的实例,这意味着您可以轻松地生成任意字符串:

arbitraryPrintableString :: Gen String
arbitraryPrintableString = getPrintableString <$> arbitrary

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-16
    • 1970-01-01
    相关资源
    最近更新 更多