0

私はいくつかのコントラクトJUnit 4テストをセットアップしています(この質問への回答のアドバイスに従います)-たとえば、インターフェースがある場合(プロジェクトで使用しているため、例にジェネリックを含めました)-しかし、これは大幅に単純化された例です。

public interface MyInterface<T> {
  public T myMethod();
}

抽象的なコントラクト テストを作成できます。例:

public abstract class AbstractMyInterfaceTest<T> {

  private final MyInterface<T> _impl;  
  // plus, store stuff to test against;

  public AbstractMyInterfaceTest(MyInterface<T> impl, ... stuff to test against){
    _impl = impl;
    // stuff to test against...
  } 

  @Test
  public void testMyMethod(){
    // test some stuff...
  }
}

...そして、実装ごとにこの抽象テストクラスを拡張します(これを使用して実行しています@RunWith(Parameterized.class))。また、いくつかの変数を渡して、インターフェースの実装を抽象テスト クラスにテストします。

ただし、実際には、一部のインターフェイスは他のインターフェイスの実装であるオブジェクトを返します。そのインターフェイスの抽象コントラクト クラスを使用して (...そして関連する変数に対して) この実装をテストできるようにしたいと考えています。たとえば、 のメソッドMyInterfaceは、インターフェースである Iterator を返す場合があります。AbstractIteratorTest値のセットに対して Iterator のコントラクト テストを実行する別の がありIterator、 の実装によって返されたが、予想される値のセットでMyInterfaceコントラクト テストに合格することを確認したいと考えています。AbstractIteratorTest

現時点では、抽象テスト クラスに以下を追加しています。

// N.b. not setting @Test - so doesn't run all tests twice...
public void runTests(){
  testMyMethod();
  // etc.
}

ただし、これは各テストを個別に実行しない (たとえばsetUp()、各テスト メソッドの前に実行する) ため、これらのコントラクト テストで実装が各テストの特定の状態にあると想定される場合は問題があります。(特定の例はIterator、各テストメソッドがテスト済みの状態を変更できるインターフェイスの実装をテストすることですIterator)

おそらくJUnit 4の機能を利用して、これを行うためのより良い方法はありますか?

注釈に関するものを見てきまし@RunWith(Suite.class)たが、それは単一のテスト クラスから複数のテスト クラスを実行することに関するものであり、実行中のさまざまなテスト クラスに変数を渡すことはできません。Suite私の問題を解決するためにこれを使用する方法があるかもしれませんが、 それが何であるかはわかりません...

4

1 に答える 1

0

まず、抽象テスト クラスをサブクラス化する場合は、 を使用する必要はありませんParameterized。サブクラス化の代わりに使用できますParameterizedが、両方が必要になることはまずありません。各実装の複数のインスタンスをテストしたい場合を除き、以下で説明します!

これを行う 1 つの方法は、返されたインスタンスのテストを単純に のサブクラスまたはパラメータ化にすることですAbstractAnotherInterfaceTest

あなたが持っているとしましょう:

public abstract class AbstractAnotherInterfaceTest {

    private AnotherInterface instance;

    protected AbstractAnotherInterfaceTest(AnotherInterface instance) {
        this.instance = instance;
    }

    @Test
    public void everythingIsOkay() {...}

}

そして、あなたは持っていました:

public class Pony implements AnotherInterface { ... }
public class PonyProducingMyInterface implements MyInterface<Pony> { ... }

あなたは書くことができます:

@RunWith(Parameterized.class)
public class PonyTest extends AbstractAnotherInterfaceTest {

    @Parameterized.Parameters
    public static Collection<Pony> ponies() {
        return Arrays.asList(
            new Pony(), // base case
            new PonyProducingMyInterface().myMethod() // testing the factory
        );
    }

    public PonyTest(Pony instance) {
        super(pony);
    }

}

new PonyProducingMyInterface().myMethod()ただし、このケースは実際には のテストですPonyProducingMyInterfaceが、 に分類されるため、これは確かに少し奇妙ですAbstractAnotherInterfaceTest

AbstractAnotherInterfaceTestのサブクラスでテストを利用する唯一の方法は、のインスタンスの子として のインスタンスをセットアップする方法を知ってAbstractMyInterfaceTestいるカスタムを作成することです。注釈を使用してプロセスをガイドすることで、おそらくそれを少し一般的にしたいと思うでしょう。ParentRunnerAbstractAnotherInterfaceTestAbstractMyInterfaceTest

于 2012-07-06T08:28:19.227 に答える