C# 在我的编译器中编写单元测试(生成IL)

C# 在我的编译器中编写单元测试(生成IL),c#,unit-testing,compiler-construction,compilation,tiger,C#,Unit Testing,Compiler Construction,Compilation,Tiger,我正在用C#编写Tiger编译器,我将Tiger代码翻译成IL 在实现AST中每个节点的语义检查时,我为此创建了许多单元测试。这非常简单,因为我的CheckSemantic方法如下所示: public override void CheckSemantics(Scope scope, IList<Error> errors) { ... } 或 但是我现在开始代码生成,我不知道在为那个阶段编写单元测试时,什么是好的实践 我正在使用ILGenerator类。我考虑过以下几点: 生成我

我正在用
C#
编写
Tiger
编译器,我将
Tiger
代码翻译成
IL

在实现AST中每个节点的语义检查时,我为此创建了许多单元测试。这非常简单,因为我的
CheckSemantic
方法如下所示:

public override void CheckSemantics(Scope scope, IList<Error> errors) {
...
}

但是我现在开始代码生成,我不知道在为那个阶段编写单元测试时,什么是好的实践

我正在使用
ILGenerator
类。我考虑过以下几点:

  • 生成我要测试的示例程序的代码
  • 将生成的代码另存为
    test.exe
  • 执行
    text.exe
    并将输出存储在
    results
  • 针对
    结果进行断言

  • 但我想知道是否有更好的方法来实现它?

    这正是我们在C#编译器团队中测试IL生成器所做的


    我们还通过ILDASM运行生成的可执行文件,并验证IL是否按预期生成,并通过PEVERIFY运行它以确保生成可验证的代码。(当然,在我们有意生成无法验证的代码的情况下除外。)

    您可以将测试视为做两件事:

  • 让您知道输出是否已更改
  • 让您知道输出是否不正确
  • 确定某个内容是否已更改通常比确定某个内容是否不正确要快得多,因此,与不正确检测测试相比,更频繁地运行更改检测测试可能是一个好策略

    在您的情况下,如果可以快速确定自生成同一可执行文件的已知良好(或假定良好)副本以来,该可执行文件未发生更改,则无需每次都运行编译器生成的可执行文件

    通常,您需要对正在测试的输出执行少量操作,以消除预期的差异(例如,将嵌入日期设置为固定值),但一旦完成操作,更改检测测试很容易编写,因为验证基本上是一个文件比较:输出是否与上次已知的良好输出相同?是:通过,否:失败

    因此,关键是,如果您发现运行编译器生成的可执行文件和检测这些程序输出中的更改时出现性能问题,您可以选择运行测试,通过比较可执行文件本身来提前检测更改。

    我创建了一个

  • 在a中,在我处理完之后,它将被删除
  • 习惯于;如果有问题,我会把它复制到一个已知的地方进行进一步的错误分析
  • 测试组件内容。在我的例子中,我主要在一个单独的AppDomain中(这样我可以在以后将其拆下)并使用一个(这样它就像一个自检程序集:)

  • 我还就如何在中扩展集成测试给出了一些想法。

    知道这一点很好。那我就那样做。我只是有点担心磁盘上运行的大量测试的性能,以及创建、读取和删除文件的性能。@OscarMederos:如果性能不够好,那么要么(1)进行分析,找出慢的地方,如果可以的话进行修复,要么(2)更改测试策略,以便在每次签入时都运行一些测试,有些测试在夜间运行,有些测试在周末运行。这样,您可以在快速发现问题和继续进行彻底测试之间取得良好的平衡。
    Assert.That(errors.Count == 0);
    
    Assert.That(errors.Count == 1);
    Assert.That(errors[0] is UnexpectedTypeError);
    Assert.That(scope.ExistsType("some_declared_type"));