【问题标题】:Writing unit tests in my compiler (which generates IL)在我的编译器中编写单元测试(生成 IL)
【发布时间】:2012-03-22 15:34:25
【问题描述】:

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

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

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

所以,如果我想为某个节点的语义检查编写一些单元测试,我所要做的就是构建一个 AST,并调用该方法。然后我可以做类似的事情:

Assert.That(errors.Count == 0);

Assert.That(errors.Count == 1);
Assert.That(errors[0] is UnexpectedTypeError);
Assert.That(scope.ExistsType("some_declared_type"));

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

我正在使用ILGenerator 类。我想到了以下几点:

  1. 生成我要测试的示例程序的代码
  2. 将生成的代码另存为test.exe
  3. 执行text.exe并将输出存储在results
  4. 断言反对results

但我想知道是否有更好的方法?

【问题讨论】:

    标签: c# unit-testing compiler-construction compilation tiger


    【解决方案1】:

    我创建了一个post-compiler in C#,并使用这种方法来测试变异的 CIL:

    1. Save the assemblytemp file 中,我完成后将被删除。
    2. 使用PEVerifycheck the assembly;如果有问题,我会将其复制到已知位置以进行进一步的错误分析。
    3. 测试程序集内容。在我的情况下,我主要是 loading the assembly dynamically 在一个单独的 AppDomain 中(所以我可以稍后将其拆除)并使用 class in there(所以它就像一个自检程序集:here's a sample implementation)。

    我还在this answer 中提供了一些关于如何扩展集成测试的想法。

    【讨论】:

      【解决方案2】:

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

      1. 让您知道输出是否已更改
      2. 如果输出不正确,请通知您

      确定某事是否已更改通常比确定某事是否不正确要快得多,因此与错误检测测试相比,更频繁地运行变更检测测试可能是一个好策略。

      在您的情况下,如果您可以快速确定可执行文件在生成同一可执行文件的已知良好(或假定良好)副本后没有更改,则您不需要每次都运行编译器生成的可执行文件。

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

      所以重点是,如果您在运行编译器生成的可执行文件并检测这些程序的输出变化时发现性能问题,您可以选择运行测试,通过比较可执行文件本身来检测更早阶段的变化。

      【讨论】:

        【解决方案3】:

        这正是我们 C# 编译器团队为测试我们的 IL 生成器所做的工作。

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

        【讨论】:

        • 很高兴知道这一点。那我就那样做。我只是有点担心运行大量测试以及在磁盘上创建、读取和删除文件的性能。
        • @OscarMederos:如果性能不够好,那么要么(1)进行分析以找出慢的地方并尽可能修复它,或者(2)改变你的测试策略,以便进行一些测试在每次签入时运行,一些测试在一夜之间运行,一些在周末运行。这样您就可以在快速发现问题和进行彻底测试之间取得良好平衡。
        猜你喜欢
        • 2015-11-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多