我最近正在编写一种小编程语言,并且已经完成了编写解析器的工作。我想为解析器编写一个自动化测试(其结果是一个抽象语法树),但我不确定哪种方式更好。
我首先尝试的是将AST序列化为S表达式文本并将其与我手工编写的预期输出文本进行比较,但它存在一些问题:
序列化文本与预期输出(如空格)之间存在微不足道的无意义差异。例如,:
之间没有区别(attribute (symbol str) (symbol length))
(已序列化)和:
(attribute (symbol str)
(symbol length))
(由我手写)的意思,但字符串比较当然区分了它们。好的,我可以通过规范化来解决它。
当测试失败时,它不会简明地显示实际树和预期树之间的差异。我想只显示差异节点,而不是整棵树。
我尝试的第二个是编写S表达式解析器并比较AST,解析器(待测试)生成AST,S-expression解析器(我刚刚实现)从手写的预期输出生成。但是我意识到S-expression也必须进行测试,这可能真是无稽之谈。
我想知道测试解析器的典型和简单方法是什么。
PS。我正在使用Java,并且不希望任何依赖于第三方库。
答案 0 :(得分:10)
假设您正在为解析器寻找完全自动化且可扩展的单元测试框架,我建议采用以下方法:
创建一组错误输入的样本。然后为每个解析器提供解析,确保解析器拒绝它们。我最好为每个定义预期输出的测试用例提供元数据 - 解析器应该生成的特定错误代码/消息。
与前一种情况一样,创建一组表示各种正确输入的样本。除了解析器接受所有输入的简单验证之外,仍然存在验证实际抽象语法树是否有意义的问题。
为了解决这个问题,我将执行以下操作:以可以安全解析的一些众所周知的格式描述每个测试用例的预期AST - 通过考虑的第三方解析器反序列化为实际的内存中AST结构无bug(适用于您的情况)。自然的选择是XML,因为大多数语言/编程框架都涵盖XML支持并提供相应的(de)序列化工具。最好的解决方案是将反序列化直接转换为AST节点类型。由于存在方便的XML可视化编辑工具,因此构建更大的测试用例是可行的。
然后我使用visitor pattern构建一个AST比较器,它将两个AST配对,并比较每对中的两个节点是否相等。但是,相等是每个AST节点类型的特定操作。
注意:
答案 1 :(得分:0)
这是什么。语法定义一种语言。语言是语法生成的字符串集,或语法的解析器接受的字符串集。
考虑到这一点,除了测试AST是否正确之外,测试解析器是否接受语言中的字符串并且拒绝您认为不属于它的字符串非常重要。
从这个意义上说,一个简单的接受或拒绝(拒绝的输入位置的奖励点)足以构建一个很好的大量测试用例。< / p>
示例:
()
(a)
((((((((((a))))))))))
((((((((((a)))))))))
(a (a (a (a (a (a (b)))))))
(((((((b) a) a) a) a) a) a)
(((((((b a) a) a) a) a) a)
((a)(a)(a)(a))
((a)(a a)(a))
(())
(()())
((()())(()())(()()))
((()())()()(()()))
...