8

コンパイラなどの複雑なユニットを単体テストするための最良のアプローチと考えられるものは何ですか?

私は何年にもわたっていくつかのコンパイラーとインタープリターを作成してきましたが、この種のコードを適切にテストするのは非常に難しいと感じています。

抽象構文木生成のようなものを取り上げるとします。TDDを使用してこれをどのようにテストしますか?

小さな構造はテストしやすいかもしれません。たとえば、次のようなものです。

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化するための最良の戦術は何でしょうか?

4

2 に答える 2

6

まず、コンパイラをテストすると、十分なテストを取得できません! ユーザーは、コンパイラによって生成された出力が常にゴールデン スタンダードであるかのように実際に依存しているため、品質には十分注意してください。したがって、可能であれば、思いつくすべてのテストでテストしてください。

次に、利用可能なすべてのテスト方法を使用しますが、必要に応じて使用してください。確かに、特定の変換が正しいことを数学的に証明できる場合があります。そうすることができるなら、そうするべきです。

しかし、私が見た内部構造のすべてのコンパイラには、ヒューリスティックと、その内部構造に最適化された多くの手作りのコードが含まれています。したがって、支援された証明方法は通常、もはや適用できません。ここで、テストが行​​われます。つまり、多くのことです。

テストを収集するときは、さまざまなケースを考慮してください。

  1. 正の標準準拠: フロントエンドは特定のコード パターンを受け入れる必要があり、コンパイラはそのコード パターンを正しく実行するプログラムを生成する必要があります。このカテゴリのテストには、テスト プログラムの正しい出力を生成するゴールデン リファレンス コンパイラまたはジェネレータが必要です。または、人間の推論によって提供された値に対するチェックを含む手書きのプログラムが含まれます。
  2. ネガティブ テスト: すべてのコンパイラは、構文エラー、型の不一致などの欠陥のあるコードを拒否する必要があります。特定のタイプのエラーおよび警告メッセージを生成する必要があります。そのようなテストを自動生成する方法を知りません。したがって、これらも人間が作成する必要があります。
  3. 変換テスト: コンパイラ (ミドルエンド) 内で凝った最適化を思いついたときはいつでも、おそらく最適化を示すコード例を念頭に置いているでしょう。そのようなモジュールの前後の変換に注意してください。コンパイラへの特別なオプション、またはそのモジュールだけがプラグインされたベアボーン コンパイラが必要になる場合があります。周囲のモジュールの組み合わせの合理的な大きなセットもテストします。私は通常、特定の変換の前後の中間表現に対して回帰テストを行い、同僚との集中的な推論によって参照を定義しました。変換の両側にコードを書くようにしてください。つまり、変換したいコード スニペットと、変換してはならないわずかに異なるコード スニペットです。

さて、これは非常に多くの作業のように聞こえます。はい、そうですが、助けがあります。世界には (C-) コンパイラ用の商用テスト スイートがいくつかあり、それらを適用するのに役立つ専門家がいます。ここに私が知っているものの小さなリストがあります:

于 2013-03-25T11:08:50.067 に答える
1

まず、解析は通常、コンパイラ プロジェクトの些細な部分です。私の経験では、10% 以上の時間がかかることはありません (C++ について話しているが、それを設計している場合はここで質問しない場合を除きます)。

それでもなお、TDD (または、どのように呼んでも) は、追加したばかりの最適化が実際に期待されるコード変換をもたらすなど、しばしば検証したいミドルエンドの開発においてシェアを持っています。私の経験から、このようなテストは通常​​、コンパイラに特別に作成されたテスト プログラムを提供し、予想されるパターンの出力アセンブリを grep することによって実装されます (このループは 4 回アンロールされましたか? メモリへの書き込みを回避できたでしょうか? など)。アセンブリの grep は、構造化された表現 (S-expr または XML) の分析ほど良くはありませんが、安価で、ほとんどの場合うまく機能します。ただし、コンパイラが成長するにつれて、サポートするのは非常に困難です。

于 2013-03-14T16:01:21.963 に答える