10

カスタム電子メール メッセージの作成を一般的に制御する一連の単体テストを含むパラメーター化されたテスト クラスがあります。現在、クラスには、パラメーター化されたクラスで使用される要因に依存する多くのテストがあり、テストの流れはすべてのテストで同じです。テストの例:

@Test
public void testRecipientsCount() {
    assertEquals(3, recipientsCount);
}

受信者のリストに追加の内部メールを追加するメール クラスに特別な機能を追加する必要がありましたが、これは一部のケースでのみ発生し、問題につながります。

作成されたメッセージの量をアサートしたいとしましょう。以前のテストでは、各ケースで同じでしたが、現在はケースによって異なります。私にとって最も直感的な方法は、if ステートメントを追加することでした。

@Test
public void testRecipientsCount(){
    if(something) {
        assertEquals(3, recipientsCount);
    }
    else {
        assertEquals(4, recipientsCount);
    }
}
...

しかし、私のより経験豊富な同僚は、テスト クラスでは if を避けるべきだと言っています (そして、私もそれに同意します)。

2 つのテスト クラスでテストを分割するとうまくいくと思いましたが、両方のクラスで冗長なコードが発生する可能性があり (非内部メッセージが作成されたかどうか、そのサイズ、内容などを確認する必要があります)、いくつかの行が追加されました。それらの中の一つ。

私の質問は次のとおりです。if や冗長なコードを使用しないようにするにはどうすればよいですか (パラメーター化されたクラスを使用しないと、さらに冗長なコードが生成されます)。

4

4 に答える 4

4

私の意見では、Junit はプロトコルのように読まれるべきです。つまり、冗長なコードを記述して、テスト ケースを読みやすくすることができます。ビジネス ロジックで考えられる各 if ステートメントと否定的なケースのテストケースを記述します。それが 100% のテスト カバレッジを得るための唯一の方法です。私は構造を使用します:

- testdata preparation
- executing logic
- check results
- clear data

さらに、大きなオブジェクトの複雑なアサートを独自の抽象クラスに記述する必要があります。

abstract class YourBusinessObjectAssert{
  public static void assertYourBussinessObjectIsValid(YourBusinessObject pYourBusinessObject,       Collection<YourBusinessObject> pAllYourBusinessObject) {
for (YourBusinessObject lYourBusinessObject : pAllYourBusinessObject) {
  if (lYourBusinessObject.isTechnicalEqual(pYourBusinessObject)) {
    return;
  }
}
assertFalse("Could not find requested YourBusinessObject in List<YourBusinessObject>!", true);
}
}

コードの複雑さが軽減され、他の開発者が利用できるようになります。

于 2013-03-01T09:15:43.220 に答える
1

私の意見では、単体テストは、可能であれば1つだけテストする必要があります。そのため、ifステートメントが必要な場合は、おそらく複数のユニットテスト(if / elseコードのブロックごとに1つ)が必要になると思います。

可能であれば、テストはストーリーのように読む必要があると思います-私の好みのレイアウト(そしてそれは私の考えではありません:-)-かなり広く使用されています)は次のとおりです:

- given:  do setup etc
- when:  the place you actually execute/call the thing under test
- expect: verify the result

単体テストテストのもう1つの利点は、障害が発生したときに原因が明確であるということです。長いテストで多くの結果が得られる場合、テストが失敗した理由を推測するのがはるかに難しくなります。

于 2013-03-01T09:29:17.867 に答える
1

パラメータ化されたテストで、あなたが求めていることをきれいに実行できるかどうかはわかりません。一部の機能のパラメーターに基づいて異なるテスト ケースの動作が必要な場合は、それらの機能を個別に (パラメーター化されていない別のテスト クラスで) テストする方がよい場合があります。

パラメータ化されたテストクラスにすべてを本当に保持したい場合は、ヘルパー関数を作成して、サンプルテストが少なくとも単純なアサーションとして読み取れるようにする傾向があります。

@Test
public void testRecipientsCount(){
    assertEquals(expectedCount(something), recipientsCount)
}

private int expectedCount(boolean which) {
    if (something){
       return 3;
    }
    else {
       return 4;
    }
}
于 2013-03-02T00:47:24.043 に答える
0

各メソッドに共通することをテストするプライベート メソッドを用意してみませんか? 次のようなものです(ただし、おそらくtestCommonStuff()メソッドの入力パラメータがあります):

@Test
public void testRecipientsCountA(){
   testCommonStuff();
   // Assert stuff for test A
}

@Test
public void testRecipientsCountB(){
   testCommonStuff();
   // Assert stuff for test B
}

private void testCommonStuff() {
   // Assert common stuff
}

これにより、冗長なコードを取得せず、テストを小さなテストに分割できます。また、実際に同じことをテストする必要がある場合は、テストでエラーが発生しにくくなります。どのテストが失敗したかはまだわかるので、トレーサビリティは問題ありません。

于 2013-03-01T09:55:05.323 に答える