4

この非常に単純なクラス階層があるとします。

public class SomeMath
{
    public int Add(int x, int y)
    {
        return x + y;
    }
}

public class MoreMath : SomeMath
{
    public int Subtract(int x, int y)
    {
        return x - y;
    }
}

クラスAddのテストを書くとき、メソッドのテストを書くべきですか? それとも、クラスMoreMathをテストしているときだけそのメソッドを気にする必要がありますか? SomeMathより一般的に: クラスのすべてのメソッドをテストする必要がありますか、それとも「新しい」メソッドのみをテストする必要がありますか?

両方の理由をいくつか思いつくことができます。たとえば、すべてのメソッドをテストすると、同じことを複数回テストすることになりますが、これはあまり良くなく、退屈になる可能性があります。ただし、すべてのメソッドをテストしないと、変更によって?SomeMathの使用法が壊れる可能性があります。MoreMathこれも悪いことです。ケースにもよると思います。私が制御できるかどうかにかかわらず、クラスを拡張するかのように。とにかく、私は完全なテストの初心者なので、これについて私が考えるよりも賢い人を知りたいです:-)

4

5 に答える 5

7

通常、子クラスが親クラスで期待される動作から変更しない限り、子クラスの動作をテストしません。同じ動作を使用している場合は、テストする必要はありません。親クラスに重大な変更を加えることを計画しているが、子クラスにはまだ古い動作が必要な場合は、最初に子クラスにテストを作成して必要な動作を定義し、次に親テストに変更を加え、その後に変更を加えます。コードの変更。これは、YAGNI の原則に従います (必要になることはありません)。実際に目的があるまで、子テストの実装を遅らせます。

于 2009-11-23T13:00:45.040 に答える
1

AddSomeMath クラスのメソッドだけをテストします。MoreMathそれを継承するだけでまったく新しいことをしない場合、両方のテストを書くことは純粋な重複コードであり、それ以上のことではありません。これらのことで少し実用的であることは常に良いことです。

于 2009-11-23T13:01:06.267 に答える
1

私の現在の場所では、インターフェイスを開発したいが、インターフェイスの各実装が正しく動作することを確認したいという同様の問題に遭遇しました(たとえば、異なるデータレイヤーは、そのレイヤーの実装に関係なく同じように動作する必要があります)。これを (NUnit を使用して) 解決した方法は、単体テスト内に継承構造を持たせることでした。

public interface ICalculator
{
  public int Add(int a, int b)
}

public class Calculator : ICalculator
{
  public int Add(int a, int b) { return a + b; }
}

public class TestCalculatorInterface
{
   public abstract SomeMath GetObjectToTest();

   [Test]
   public void TestAdd()
   {
       var someMath = GetObjectToTest();
       ...
   }
}    

[TestFixture]
public class TestCalculator: TestCalculatorInterface
{
   public virtual Calculator GetObjectToTest() { return new Calculator(); }
}

ベース インターフェイス test には[TestFixture]属性はありませんが、すべてのテスト メソッドには[Test]属性があります。TestCalculatorクラスは[TestFixture] ですが、基本クラスからすべてのテストを継承するため、サブクラスはそのインターフェイスをテストするためのオブジェクトを提供するだけの責任を負います。

私はあなたのケースに同様のパターンを採用するので、テストはすべてのクラスに対して実行されますが、1 回しか書き込まれません。

于 2009-11-23T13:48:26.957 に答える
0

のテスト クラスをMoreMathのテスト クラスから継承して、SomeMathそのクラスのすべてのテストを継承します。つまり、新しい機能に対して追加のテストを作成するだけで済みますが、サブクラスの機能はすべて完全にテストされています。

于 2009-11-23T13:29:46.463 に答える
0

まず第一に、どちらかを行うかどうかの決定に影響を与える可能性のある要因が少なくとも 2 つあります。

  • 継承の目的は何ですか?
  • 問題のテストの目的は何ですか?

TDD のシナリオでは、MoreMath が SomeMath から派生していることを検証する 1 つのテスト ケースを作成し、SomeMath から継承されたすべてのメンバーがカバーされると考える傾向があります。

ただし、これは、設計の観点からは、MoreMath が SomeMath から派生した重要な設計側面であることを意味します。SomeMath をポリモーフィックな方法で使用する場合、これは間違いなく当てはまります。ただし、単に継承を再利用のために使用する場合はそうではありません (ただし、推奨されません)。

後者の場合 (継承は再利用のために使用されます)、親クラスと子クラスの間に概念的なつながりはなく、将来的に継承を壊したくなるかもしれません。このような場合、親が正しいことを検証するテストを行うことは、安全対策として不十分です。

品質保証 (QA) の観点から、すべてのクラスのすべてのメンバーを厳密にテストする必要があります。これは、仮想メソッドが予期しない方法でオーバーライドされていないことを確認する必要があるため、テスト コードが同じであっても、子クラスごとにテスト コードを繰り返す必要があることを意味します。ただし、DRY を維持するには、それらをパラメーター化されたテストとして記述したり、おそらくPexなどのツールを使用したりできます。

個人的には、QA フェーズに到達することはめったにありません。通常、TDD 中に作成されたテスト スイートは適切なセーフティ ネットですが、それはすべて、作成するソフトウェアの種類によって異なります。

于 2009-11-23T13:14:07.650 に答える