Unit testing 编译器的单元测试
对复杂单元(如编译器)进行单元测试的最佳方法是什么 这些年来,我已经编写了一些编译器和解释器,我确实发现这种代码很难以一种好的方式进行测试 如果我们采取类似于抽象语法树生成的方法。您将如何使用TDD对此进行测试 小构造可能很容易测试。 e、 g.大致如下:Unit testing 编译器的单元测试,unit-testing,parsing,tdd,compiler-theory,abstract-syntax-tree,Unit Testing,Parsing,Tdd,Compiler Theory,Abstract Syntax Tree,对复杂单元(如编译器)进行单元测试的最佳方法是什么 这些年来,我已经编写了一些编译器和解释器,我确实发现这种代码很难以一种好的方式进行测试 如果我们采取类似于抽象语法树生成的方法。您将如何使用TDD对此进行测试 小构造可能很容易测试。 e、 g.大致如下: string code = @"public class Foo {}"; AST ast = compiler.Parse(code); 因为这不会生成很多ast节点 但如果我真的想测试编译器是否可以为类似方法的东西生成AST: [Tes
string code = @"public class Foo {}";
AST ast = compiler.Parse(code);
因为这不会生成很多ast节点
但如果我真的想测试编译器是否可以为类似方法的东西生成AST:
[TestMethod]
public void Can_parse_integer_instance_method_in_class ()
{
string code = @"public class Foo { public int method(){ return 0;}}";
AST ast = compiler.Parse(code);
你会坚持什么?
手动定义一个表示给定代码的AST,并断言生成的AST符合手动定义的AST,这看起来非常复杂,甚至可能容易出错
那么,对于这样的复杂场景,TDD的最佳策略是什么呢?首先,解析通常是编译器项目的一个微不足道的部分。从我的经验来看,它不需要超过10%的时间(除非我们在谈论C++,但是如果你在设计C++,你就不会问问题),所以你不愿意把你的时间投入到语法分析器测试中。
尽管如此,TDD(或者你怎么称呼它)在开发中间端时仍占有一席之地,在这个中间端,你经常想要验证,例如,你刚刚添加的优化确实会导致预期的代码转换。根据我的经验,像这样的测试通常是通过给编译器精心编制的测试程序和对预期模式的输出程序集进行grepping来实现的(这个循环是否展开了四次?我们是否设法避免了内存写入是这个函数?等等)。Grepping assembly不如分析结构化表示(S-exprs或XML),但它价格便宜,在大多数情况下工作良好。但是,随着编译器的增长,支持它是非常困难的。首先,如果您测试编译器,您将无法获得足够的测试!用户真正依赖于编译器生成的输出,就好像它始终是一个黄金标准一样,所以要真正注意质量。所以,如果你可以,用你能想出的每一个测试来测试 其次,使用所有可用的测试方法,但在适当的地方使用它们。事实上,你可以从数学上证明,某个变换是正确的。如果你能做到这一点,你应该这样做 但我见过的每一个编译器的内部都包含了启发法和大量优化的手工代码;因此,辅助证明方法通常不再适用。在这里,测试已经到位,我的意思是很多
收集测试时,请考虑不同的情况:
- C编译器验证套件
- GCC和LLVM环境中的测试
- 你说得对!或谷歌“编译器测试套件”