7

コマンドごとに32ビットのオペコードを生成するパーサーを作成しています。たとえば、次のステートメントの場合:

set lcl_var = 2

私のパーサーは次のオペコードを生成します。

// load immdshort 2 (loads the value 2)
0x10000010
// strlocal lclvar (lcl_var is converted to an index to identify the var)
0x01000002

lcl_var何でもかまいません。つまり、任意の変数を指定できることに注意してください。このための単体テストケースを作成するにはどうすればよいですか?値のハードコーディングを回避できますか?それを一般的にする方法はありますか?

4

7 に答える 7

2

パーサーをどのように構築したかによって異なります。Unit-Test は、単一の UNIT をテストします。

したがって、パーサー全体を 1 つのユニットとしてテストする場合は、コマンドのリストを指定して、正しいオペコードが生成されることを確認できます (テストの作成時に手動で確認しました)。コマンドごとにテストを記述し、通常の使用法、エッジケースの使用法、エッジケースを超えた使用法をテストできます。たとえば、次のことをテストします。

lcl_var = 2 を設定

結果:

0x10000010 0x01000002

0、-1、MAX_INT-1、MAX_INT+1、... についても同様です。

これらの値の正しい結果がわかります。異なる変数についても同様です。

于 2009-01-14T10:19:36.730 に答える
1

あなたの質問が「入力と出力の組み合わせごとに 1 つの xUnit テストを作成せずに、異なる入力と期待値で同じテストを実行するにはどうすればよいですか?」

それに対する答えは、RowTest NUnit 拡張のようなものを使用することです。最近、ブログにクイックブートアップの投稿を書きました。これの例は次のようになります

[TestFixture]
    public class TestExpression
    {
        [RowTest]
        [Row(" 2 + 3 ", "2 3 +")]
        [Row(" 2 + (30 + 50 ) ", "2 30 50 + +")]
        [Row("  ( (10+20) + 30 ) * 20-8/4 ", "10 20 + 30 + 20 * 8 4 / -")]
        [Row("0-12000-(16*4)-20", "0 12000 - 16 4 * - 20 -")]
        public void TestConvertInfixToPostfix(string sInfixExpr, string sExpectedPostfixExpr)
        {
            Expression converter = new Expression();
            List<object> postfixExpr = converter.ConvertInfixToPostfix(sInfixExpr);

            StringBuilder sb = new StringBuilder();
            foreach(object term in postfixExpr)
            {
                sb.AppendFormat("{0} ", term.ToString());
            }
            Assert.AreEqual(sExpectedPostfixExpr, sb.ToString().Trim());
        }
于 2009-02-04T09:20:28.263 に答える
1
int[] opcodes = Parser.GetOpcodes("set lcl_var = 2");
Assert.AreEqual(2, opcodes.Length);
Assert.AreEqual(0x10000010, opcodes[0]);
Assert.AreEqual(0x01000002, opcodes[1]);
于 2009-01-14T15:25:58.220 に答える
0

テストに使用する方法論または特定のテクノロジーを探しているかどうかは明確ではありません。

方法論に関する限り、大規模な単体テストは行いたくないかもしれません。おそらく、より良いアプローチは、ドメイン固有言語でいくつかのプログラムを作成し、次にオペコードを実行して結果を生成することです。次に、テストプログラムはこの結果をチェックします。このようにして、大量のコードを実行できますが、最後に1つの結果のみを確認してください。単純なものから始めて、明らかなバグを洗い流し、より難しいバグに移行します。生成されたオペコードを毎回チェックする代わりに。

取るべき別のアプローチは、予想されるオペコードとともにドメイン固有言語でプログラムを自動的に生成することです。これは、次のような一連のプログラムを生成するperlスクリプトを作成するように非常に簡単です。

lcl_var=2を設定します

lcl_var=3に設定

正しい出力を持つ言語のテストプログラムのスイートができたら、逆方向に進んで、各オペコードをチェックする単体テストを生成できます。すでにオペコードを持っているので、パーサーの出力が正しいかどうかを調べることが問題になります。そのコードを確認します。

私はcppunitを使用していませんが、cppunitに非常によく似た社内ツールを使用しました。cppunitを使用して単体テストを実装するのは簡単でした。

于 2009-02-06T16:52:54.603 に答える
0

パーサーを作成する言語を指定しないので、議論のために、オブジェクト指向言語を使用していると仮定します。

この場合、依存性注入がここで役立つ可能性があります。放出されたオペコードの宛先がクラスのインスタンス(たとえば、Fileなど)である場合は、放出されたコードの宛先として使用するそのタイプのオブジェクトを取得するコンストラクターをエミッタークラスに与えてみてください。次に、単体テストから、宛先クラスのサブクラスのインスタンスであるモックオブジェクトを渡し、特定のステートメントに対して発行されたオペコードをキャプチャし、それらが正しいことを表明できます。

デスティネーションクラスを簡単に拡張できない場合は、デスティネーションクラスとモッククラスの両方が実装できるインターフェイスをそれに基づいて作成することをお勧めします。

于 2009-01-13T15:59:05.063 に答える
0

何をテストしますか? 正しい「ストア」命令が作成されているか知りたいですか? 正しい変数がピックアップされているかどうか 知りたいことを決めれば、テストは明白になります。何を達成したいのかがわからない限り、未知のものをテストする方法はわかりません。

それまでは、簡単なテストを書いてください。明日か明後日、何かが壊れたので、あなたはまたこの場所に来るでしょう。その時点で、自分が何をしたいのかがより明確になり、テストの設計がより簡単になる可能性があります。

今日、明日の自分になろうとしないでください。

于 2009-02-24T14:21:32.323 に答える
0

私が理解しているように、最初に特定の例のテストを作成します。つまり、パーサーへの入力は次のとおりです。

set lcl_var = 2

出力は次のとおりです。

0x10000010 // load immdshort 2
0x01000002 // strlocal lclvar 

そのテストに合格するように本番コードを実装し、それをリファクタリングした場合、満足できない場合は、ローカル変数を処理し、別のローカル変数を使用して別のテストを作成し、合格するかどうかを確認します。例: 入力による新しいテスト:

set lcl_var2 = 2

そして、必要な別の出力を期待する新しいテストを作成します。本番コードが十分に堅牢であることに満足するまで、これを続けてください。

于 2009-01-14T10:18:22.287 に答える