3

私は主力製品の単体テストを書いていますが、懸念事項が 1 つあります。差別化の方法です。

  • テストがうまくいかなかったために失敗したテスト (たとえば、バグが見つかり、それに対する非回帰テスト)
  • テストの別の予期しない部分が失敗したために失敗したテスト (テストが間違っているか、未知のバグが発生したため)

最初のものには確かにjUnit Assertフレームワークがありますが、2番目のものには何がありますか?

例: 私の単体テストでは、c() が MyException をスローしないことをテストしていますが、c() を実行するには、最初に a() を実行し、次に b() を実行する必要があります。どちらも MyException() をスローできるため、次のように記述します。

@Test
public void testC() {
  a();
  Object forC = b();
  try {
    c(forC);
  } catch (MyException e) {
    Assert.fail("....");
  }
}

ただし、a または b によってスローされる可能性のある MyException を処理し、forC が null であってはならないという事実も処理する必要があります。これを行う最善の方法は何ですか?

  • a または b と Assert.fail によってスローされた MyException をキャッチしますが、a と b はこのテストではテストされないため、失敗したときにテスト失敗としてマークされるべきではありません。この時点では a();b(); ではなく b();a() を実行する必要があるため、後で失敗する可能性があります。
  • testC が MyException をスローすると、テストは "MyException" で失敗しますが、MyException はテストが間違って記述されていることを通知しないため、これは誤解を招きます。すべてのテストは、それぞれ独自の例外で失敗します。この場合、forC が null の場合は NullPointerException のようなものもスローする必要がありますが、これにもセマンティックはありません。
  • a および b によってスローされた MyException をキャッチして、TestCorruptedException のように、テストが間違っている可能性があることを示す例外にラップします。しかし、jUnitでそのような例外を見つけることができなかったため、jUnitではそのように認識されませんでした(それは私にとっては問題ありません)。また、もちろん複数のモジュール、プロジェクトなどに分割されているすべての単体テストからこの例外を知る必要があります...したがって、これは実行可能ですが、依存関係が追加されます。

この問題の解決策は何ですか? 私はおそらく2番目に行くでしょうが、上で説明したように満足していません.

4

5 に答える 5

5

単体テストの要は、必要最小限のコードをテストすることです。そうしないと、エンドツーエンドの機能を探している統合テストスペースに間違いなく分類されます。

a()独自のテストクラスで作成およびテストでき、独自のテストクラスでも作成およびテストできることを証明できる場合b()、上記のテストではのテストを無視しa()b()代わりに、勝った既知の値を使用できます。失敗しないでください。これは通常、モックオブジェクトを使用することで満たされます。

モックオブジェクトとして作成されたa()とb()を使用すると、個別c()にテストできます。a()とb()を分離してc()をテストすることが不可能であることがわかった場合、これは、関心の分離があるようにコードを変更する必要があることを示しています。これは通常、a()とb()の依存関係をc()に注入することで満たされます。

単体テストでモックオブジェクトをいつ使用するかについてのこの投稿は、このトピックにさらに光を当てるのに役立つ可能性があります。

于 2012-07-13T16:11:22.153 に答える
1

賢明な言葉-ユニットテストでは決してこれを行わないでください

 try {
    c(forC);
  } catch (MyException e) {
    Assert.fail("....");
  }

これは、コードで作業しなければならない人にとっては本当に厄介な副作用です。例外の元の原因が失われます。これは、修正開発者がテストに参加してデバッグするか、try / catchブロックを削除して、例外の根本原因を確認する必要があることを意味します。

テストで例外がスローされてはならない場合は、そのままにします。テストは失敗し、テストを実行している開発者は、最初に例外の原因をコンソール/ログで簡単に確認できます。@piotrekからのアドバイスを受けて、テストをできるだけ簡単にしてください。不正な形式のテストからこの構成を削除しなければならなかった回数を数えることはできません。

于 2012-07-13T16:15:44.907 に答える
0

かっこいい質問!:)

私が書くすべての単体テストは、この構造に従います。

// Given
 setup for the test

// When
what i specifically test

// Then
my assertions

あなたの例では、試してみる前にセットアップが行われていると思います。テストの準備のために何かを呼び出す必要があります、それは大丈夫です。

しかし、あなたがあなたの仕事をうまくやれば、a(); およびb(); 他の場所でテストされています。したがって、これらのメソッドの1つにバグがある場合、他のテスト、つまりそれらのテストは失敗します。それがあなたがそれが壊れているところを区別する方法です。

GivedとThenは決して壊れてはなりません。あなたはいつをテストしています。

a()とb()がわからない場合は、それらをモックします。

そして最後のケースでは、例外を区別したい場合は、メッセージをアサートします。

于 2012-07-13T16:14:22.107 に答える
0

例外をキャッチするのではなく、テスト メソッドからスローします。JUnit は、テストの失敗とテスト エラーの違いを示します。

public void test() throws MyException {
    boolean result = instance.doStuff();
    Assert.true(result);
}

例外が予想される場合は、次のようにします。

public void test() {
    try {
        instance.doStuff();
        Assert.fail("Expected MyException");
    }
    catch(MyException e) {
        // expected
    }
}
于 2012-07-13T19:02:04.653 に答える
0

有名な問題: 誰が私たちのテストをテストしますか? 短い答え: 区別することはできません。テスト間の依存関係をいつでも定義できます (一部のテスト フレームワークでは)。1 つのテストが失敗すると、それに依存するすべてのテストは実行されません。テスト コードが正しいかどうかはわかりません。そのため、できるだけシンプルにする必要があります。また、コードを修正する前に実行する必要があります。このようにして、コードが修正されたと思っているのに、実際にはテストが間違っているためにパスするという状況を回避できます。

于 2012-07-13T16:05:29.003 に答える