8

我想为 Parsec 解析器编写一个测试。这是解析器和数据结构的示例:

data Event = Event { keyEvent :: String }
    deriving Show

parseKey :: Parser Event
parseKey = do
             char '<'
             k <- many1 (letter <|> digit <|> oneOf "_")
             char '>'
             return $ Event k

我知道我需要检查parse = parse . pretty . parse财产。但是我应该如何生成正确不正确的测试用例呢?一般来说,我应该如何为给定的BNF生成测试用例?我知道instance Arbitrary,但对此没有太大帮助。

如果您为这个简单的解析器提供一个注释良好的生成器示例,我将不胜感激。

4

1 回答 1

13

测试解析器并不完全是微不足道的。(取决于事物的复杂性,与所有测试一样。)

您可以做的一件事是编写一个Arbitrary实例,该实例构造所有有效的表达式(或您尝试解析的任何表达式),然后检查您是否漂亮地打印该事物然后解析结果字符串,您会得到什么你开始了。

这样做有几个问题:

  • 如果答案是错误的,那是什么坏了?解析器还是打印机?

  • 如果你正在解析的东西足够复杂,以至于有可选的括号和东西,你需要检查它在有和没有可选括号的情况下是否有效。通常,您漂亮的打印机只会以一种或另一种方式做到这一点。

  • 这不会检查垃圾输入是否确实被拒绝(并且不会被解析为奇怪的东西)。例如,我写了很多 Parsec 解析器,如果语法错误发生在输入的末尾,它们会默默地忽略它。

一般来说,我所知道的测试解析器的唯一真正彻底的方法就是手动编写大量的手动测试。(并且每次您发现解析错误的内容时,为其添加另一个测试用例。)例如,这基本上就是 GHC 对他们的测试套件所做的事情。

当然,这取决于您的解析器有多复杂,以及您想要多少保证……如果您只是解析 JSON,您可能可以相当轻松地对其进行测试。如果你正在解析 Markdown 之类的东西......我的上帝怜悯你的灵魂!

于 2012-10-19T20:39:57.900 回答