web-dev-qa-db-ja.com

メソッドのテストでTDDの再設計後にメソッドがプライベートになるとどうなりますか?

他のキャラクターを攻撃するキャラクターなどを使ったロールゲームの開発を始めたとします。

TDDを適用して、Character.receiveAttack(Int)メソッド内のロジックをテストするテストケースをいくつか作成します。このようなもの:

_@Test
fun healthIsReducedWhenCharacterIsAttacked() {
    val c = Character(100) //arg is the health
    c.receiveAttack(50) //arg is the suffered attack damage
    assertThat(c.health, is(50));
}
_

receiveAttackメソッドをテストする10のメソッドがあるとします。ここで、メソッドCharacter.attack(Character)receiveAttackメソッドを呼び出す)を追加し、いくつかのTDDサイクルでそれをテストした後、決定を行います:Character.receiveAttack(Int)private

以前の10件のテストケースはどうなりますか?それらを削除する必要がありますか?メソッドpublicを保持する必要がありますか(そうは思いません)?

この質問は、プライベートメソッドをテストする方法ではなく、TDDを適用する場合の再設計後にそれらを処理する方法についてです

29
Héctor

TDDでは、テストは設計の実行可能なドキュメントとして機能します。デザインが変更されたので、当然、ドキュメントも変更する必要があります。

TDDでは、attackメソッドが出現する可能性がある唯一の方法は、失敗したテストパスを作成した結果であることに注意してください。つまり、attackは他のテストによってテストされています。つまり、間接的にreceiveAttackattackのテストでカバーされます。理想的には、receiveAttackを変更すると、attackのテストの少なくとも1つが失敗するはずです。

そうでない場合、receiveAttackには不要な機能が存在し、存在しなくなります。

したがって、receiveAttackattackを通じてすでにテストされているため、テストを継続するかどうかは関係ありません。 Ifテストフレームワークを使用すると、プライベートメソッドを簡単にテストできます。ifプライベートメソッドをテストする場合は、保持できます。ただし、テストの適用範囲と信頼性を失うことなく、それらを削除することもできます。

52
Jörg W Mittag

メソッドがテストを必要とするほど複雑である場合、それはいくつかのクラスでパブリックでなければなりません。だからあなたはからリファクタリングします:

public class X {
  private int complexity(...) {
    ...
  }
  public void somethingElse() {
    int c = complexity(...);
  }
}

に:

public class Complexity {
  public int calculate(...) {
    ...
  }
}

public class X {
  private Complexity complexity;
  public X(Complexity complexity) { // dependency injection happiness
    this.complexity = complexity;
  }

  public void something() {
    int c = complexity.calculate(...);
  }
}

X.complexityの現在のテストをComplexityTestに移動します。次に、複雑さをあざけってX.somethingにテキストを送信します。

私の経験では、より小さなクラスとより短いメソッドに向けてリファクタリングすることには大きなメリットがあります。それらは理解しやすく、テストも簡単で、予想以上に再利用されることになります。

23
kevin cline

ReceiveAttackメソッドをテストする10のメソッドがあるとします。次に、Character.attack(Character)メソッド(receiveAttackメソッドを呼び出す)を追加し、いくつかのTDDサイクルでそれをテストした後、決定を行います。Character.receiveAttack(Int)はプライベートである必要があります。

ここで覚えておくべきことは、あなたが下している決定がAPIからメソッドを削除するであることです。後方互換性の礼儀は示唆するでしょう

  1. 削除する必要がない場合は、APIに残してください。
  2. 削除する必要がない場合まだの場合は、非推奨としてマークし、可能であれば、サポート終了がいつ発生するかを文書化します。
  3. 削除する必要がある場合は、メジャーバージョンが変更されています

APIがメソッドをサポートしなくなると、テストは削除または置換されます。その時点で、プライベートメソッドは実装の詳細であり、リファクタリングできるはずです。

その時点で、テストスイートが純粋にパブリックAPIを介して対話するのではなく、実装に直接アクセスする必要があるかどうかという標準的な質問に戻ります。プライベートメソッドは、置き換えることができるはずですテストスイートが邪魔にならない限り。したがって、私はそれと関連するテストがなくなることを期待します-廃止されるか、実装を個別にテスト可能なコンポーネントに移行します。

6
VoiceOfUnreason