web-dev-qa-db-ja.com

テストされたクラスをスパイすることは悪い習慣ですか?

私はクラスの内部呼び出しが通常であるプロジェクトに取り組んでいますが、結果は多くの場合単純な値です。例(実際のコードではない):

public boolean findError(Set<Thing1> set1, Set<Thing2> set2) {
  if (!checkFirstCondition(set1, set2)) {
    return false;
  }
  if (!checkSecondCondition(set1, set2)) {
    return false;
  }
  return true;
}

実際の条件の実装ではなく条件システムをテストしたいだけなので、このタイプのコードの単体テストを書くのは本当に難しいです。 (私は別のテストでそれを行います。)実際、条件を実装する関数を渡して、テストで単にモックを提供した方が良いでしょう。このアプローチの問題はノイズです:私たちはジェネリックをたくさん使用します

実用的なソリューション。ただし、テストしたオブジェクトをspyにして、内部関数の呼び出しをモックアウトすることです。

systemUnderTest = Mockito.spy(systemUnderTest);
doReturn(true).when(systemUnderTest).checkFirstCondition(....);

ここでの懸念は、SUTの実装が効果的に変更されていることと、テストを実装と同期させておくことが問題になる可能性があることです。これは本当ですか?この内部メソッド呼び出しの混乱を回避するためのベストプラクティスはありますか?

アルゴリズムの一部について話しているので、それをいくつかのクラスに分割することは望ましい決定ではない場合があることに注意してください。

14
allprog

単体テストでは、テストするクラスをブラックボックスとして扱う必要があります。重要なことは、そのパブリックメソッドが期待どおりに動作することです。クラスが内部状態とプライベートメソッドを通じてこれをどのように達成するかは重要ではありません。

この方法で意味のあるテストを作成することが不可能だと感じた場合、それはクラスが強力すぎて、実行しすぎていることを示しています。それらの機能の一部を、個別にテストできる個別のクラスに移動することを検討する必要があります。

15
Philipp

findError()checkFirstCondition()の両方がクラスのパブリックメソッドである場合、findError()は事実上、同じAPIからすでに利用可能な機能のファサードです。何も問題はありませんが、既存のテストと非常によく似たテストを作成する必要があるということです。この重複は、単にパブリックインターフェイスの重複を反映しています。これは、この方法を他の方法と異なる方法で処理する理由にはなりません。

4
Kilian Foth

ユニットテストは契約をテストする必要があります。それは彼らにとって唯一の重要なことです。コントラクトの一部ではないものをテストすることは、時間の浪費であるだけでなく、エラーの潜在的な原因でもあります。開発者が実装の詳細を変更するときにテストを変更するのを見たときはいつでも、警報ベルが鳴るはずです。その開発者は(意図的かどうかにかかわらず)間違いを隠している可能性があります。 故意に実装の詳細をテストすると、この悪い習慣が強制され、エラーがマスクされる可能性が高くなります。

内部呼び出しは実装の詳細であり、パフォーマンスの測定にのみ関係があります。これは通常、単体テストの仕事ではありません。

4
itsbruce

最初に、私はあなたが書いたサンプル関数について何をテストするのが難しいのだろうと思いますか?私の知る限り、さまざまな入力を渡して、正しいブール値が返されることを確認するだけです。何が欠けていますか?

スパイに関しては、スパイとモックを使用するいわゆる「ホワイトボックス」テストは、書き込むコードが非常に多いためだけでなく、実装が常にあるため、作成する作業が桁違いに多くなります。変更した場合は、テストも変更する必要があります(インターフェースが同じ場合でも)。また、この種のテストは、ブラックボックステストよりも信頼性が低くなります。これは、追加のすべてのテストコードが正しいことを確認する必要があるためです。また、ブラックボックスユニットテストがインターフェイスと一致しない場合は失敗することを信頼できます。 、テストで実際のコードの多くがテストされないこともあるため、モックのみを使用しているため、モックの過剰使用については信頼できません。モックが正しくない場合、おそらくテストは成功しますが、コードはまだ壊れています。

ホワイトボックステストの経験がある人なら誰でも、それらを作成して保守するのが面倒だと言うことができます。ホワイトボックステストは信頼性が低いという事実と相まって、ほとんどの場合、はるかに劣っています。

2
B T