5

私は、ユニットテストと統合テストを備えた分散システムを使用しています。統合テストと単体テストの間でコードを再利用することで、時間とメンテナンスの労力を節約しようとしています。このために、私はインターフェースと2つのクラスを実装しました:偽物と本物。のクラスはスタブ化されたデータを返し、実際のクラスは他の分散サービスを数回呼び出します。

私のプロジェクトの現在の構造

/ BaseTest              
   インターフェイスIFoo
-------------------------------------
/単体テスト
   クラスFakeFoo:IFoo

   [テストフィクスチャ]
   class FooTest {...}//FakeFooを使用します
-------------------------------------
/ IntegrationTest
   クラスRealFoo:IFoo

   [テストフィクスチャ]
   class FooTest {...}//RealFooを使用します

どういうわけか両方のテストでコードを再利用したいので、テストがある場合

[Test]
public void GetBarIsNotNullTest()
{
    var foo = IoC.Current.Resolve<IFoo>();
    Bar actual = foo.GetBar();
    Assert.IsNotNull(actual);   
}

このテストを両方の実装で実行したい:RealFooFakeFooこれまで、 /UnitTestプロジェクトと/IntegrationTestプロジェクトの間でテストをコピーして貼り付けることを考えていましたが、これは正しく聞こえません。

システムはC#で記述されていますが、この質問は言語に依存しないと思います。

誰かがより良いアイデアを持っていますか?私はこれを間違っていますか?

4

3 に答える 3

5

他の人の答えには良い点がありましたが、これが私がやったことです

ユニットテストと統合テストの基本クラスを作成しました

[TestFixture]
public class FooBase
{
    [Test]
    public void GetBarIsNotNullTest()
    {
        var foo = IoC.Current.Resolve<IFoo>();
        Bar actual = foo.GetBar();
        Assert.IsNotNull(actual);   
    }

    //many other tests  
}

そして、から派生した2つのクラスFooBase。これらのクラスには、他にはSetUp何もありません。すなわち:

[TestFixture]
public class UnitTestFoo : FooBase
{
    [SetUp]
    public void SetUp()
    {
        IoC.Current.Register<IFoo, FakeFoo>();        
    }

    //nothing else here
}

[TestFixture]
public class IntegrationTestFoo : FooBase
{
    [SetUp]
    public void SetUp()
    {
        IoC.Current.Register<IFoo, RealFoo>();        
    }

    //nothing else here
}

したがって、ここでテストを実行すると、親クラスで定義されたテストが、FooBase単体テストクラスと統合テストクラスに対して、独自のオブジェクトとオブジェクトで2回実行されます。これは、テストフィクスチャの継承のために機能します。

于 2012-07-25T14:09:36.990 に答える
2

テストシナリオにひどく問題があります。

最初にユニットテストを見てみましょう。予測可能な結果を​​もたらす依存関係スタブがあります。スタブ構成に従って期待される結果が得られるCUTがあります。ここまでは順調ですね。

だが。統合テストにテストコード(アサーション)を再利用する場合、実際には、実際の依存関係の実装で、単体テストでスタブが行ったのと同じ結果が得られることを期待していることを意味します。もしそうなら、依存関係をテストしてそれらの結果を出し、コードのレイヤー全体をスキップしてみませんか?

アップデート

あなたの例は間違っています。FakeFooはスタブであり、テストする必要はありません。一部のサービスに依存するクラスをテストするためにスタブを実行します。Barしたがって、に依存するクラスをテストしていると仮定します。これは、次のIFooことを意味します。

[Test]
public void GetBarIsNotNullTest()
{
    var bar = IoC.Current.Resolve<Bar>();
    var actual = bar.GetDon();
    Assert.IsNotNull(actual);   
}

IFooテストでのさまざまな実装を使用しています。

私の立場を明確にするために

テストでActステージとAssertステージをコピーしているため、 CUTで同じコードパスをテストしている可能性があります(Bar)。これはテストの複製を意味し、コードの複製に勝るものはありません。

Bar偽物(単体テスト)を使用して、すべてのコードパスでCUT()が適切であることを確認する必要があります。次に、依存関係RealFoo)が期待されるデータを返すことを確認する必要があります(分散サービスで機能するため、統合テストになります)。すでに完全にテストされているため、でテストBarする必要はありません。RealFoo

于 2012-07-25T13:29:05.390 に答える
1

独自の偽の実装を作成しても、時間を節約することはできません。依存関係のモックを作成する方がはるかに簡単です。

Mock<IFoo> fooMock = new Mock<IFoo>();

そして最悪の部分は、モックオブジェクトを設定することです。さまざまなテストシナリオに対してさまざまな結果を設定できます。

fooMock.Setup(f => f.Bar).Returns(true);
// or
fooMock.Setup(f => f.Bar).Returns(false);

これは偽物では不可能です。プロパティの実装が1つあり、またはのBarいずれかが返されtrueますfalse

更新:単体テストと統合テストの唯一の違いは、Arrangeテストの一部です。Act同じでAssertある可能性があります(相互作用テストなしで状態テストのみを行う場合)。しかしArrange、完全に異なります。直接依存のインスタンスを作成するだけではありません。モックを使用する場合は、SUTが使用するメンバーの戻り結果を設定する必要があります。テストシナリオを再現するには、これで十分です。ただし、実際のオブジェクトの場合は、スタックのすべての依存関係を、現在のテストシナリオで必要な状態に設定する必要があります。

于 2012-07-25T13:41:12.517 に答える