2016-11-30 3 views
0

私はユニットテストに関する質問があります。UnitTestingヘルプ:スタブを使用していますか?

私は関数を呼び出して関数Aと呼び、クラスBのインスタンスを入力として受け取り、真または偽を返します。

私のテストでは、どうにかして関数Aに渡すオブジェクトを作成する必要があります。私が現在行っていることは、そのコンストラクタを使ってクラスBを初期化し、そのメソッドのいくつかを呼び出してそれを作成し、正しい構造体を作成し、それを関数Aに渡すことです。良いパターンです:特にクラスBのメソッドにバグがある場合や、インターフェースを変更する場合はどうなりますか?

だから私はスタブを使う必要があると思います。私のクラスBと基本的に同じ構造を持つクラスを書くのは変です。また、関数Aは最終的にクラスBで動作するので、クラスBのインターフェースを変更すると、関数Aのテストがクラッシュして、新しいインターフェースを受け入れるために関数Aを変更するよう指示されます。

正しいパターンは何ですか?

注:これは主に意見に基づいていると思われる場合は、次のように改訂してください。「ユニットテストの技術」で提唱されている原則によれば、ここでは何がベストでしょうか? - 正気です、あなたの残りのために、より大きな視点で答えを書くこと自由に感じ

編集

私は明確にすべき、関数Aの唯一の目的は、クラスBのインスタンスを取ることで、特定の条件が満たされていることを確認します。今、私はクラスBの代わりにスタブを作成することができましたが、これは意味をなさないとは確信していません。むしろ意味がないように思えます。一方、Bを初期化するには、classB.addData(randomData)のような処理を行います。このコードが失敗するとどうなりますか?実際の問題は、クラスB

編集2 より明示的に機能が何を示していくつかのコードの初期化をしている間、私は、関数Aのためのテストでエラーが発生します。方法はより複雑ですが、それ以外はまったく同じ

def functionA(objectB): 
    return objectB.data < 10 

def testFunctionA(): 
     objectB = classB() 
     objectB.addData(19)  #Is this a problem or should I stub objectB? 

     assert(functionA(objectB) is False) 
+0

具体的な答えを具体的に投稿する必要があると思います。今、疑問はすべて抽象的で理論的であり、抽象的な答えに役立ちます。具体的な回答が必要な場合は、問題を示すコードが役立ちます。 – Kritner

+0

@Kritner私はいくつかのコードを追加しました..実際のコードは本質的にこれと同じです。メソッドは長いかもしれませんが、本質的に同じ – Ant

+0

はこのpythonですか?私はPythonを知らないのですが、 'functionA'は' objectB.data' gt 10が 'true'を返し、そうでなければ' false'を返します。それがあなたの主張が失敗しないだろうか? – Kritner

答えて

0

コメントのためにあまりにも長いです除いて実際のコードは、まったく同じです:

ユニットテストABの範囲で問題はありません。 Aの異なるブランチをテストするためにモック/スタブ/何でも使用しても問題ありません。

Bの実装がいくつかの点で変更されている場合は、Aの実装に関しては理想的ではありません(理想的なシナリオでは、例は非常に抽象的です)。 Bの実装を大幅に変更してABという異なるメンバーを探している場合は、Aユニットテストに影響を与える可能性があります。 Bの場合、Aが変更に依存するメンバーに到着すると、Bの模擬バージョンでは問題になりません。

それは、しかしBのユニットテストには関係します。

具体的なことがあれば詳しく説明できますが、今は抽象的な質問のためのほとんどの抽象的な答えです。

def functionA(objectB): 
    return objectB.data < 10 

def testFunctionA(): 
     objectB = classB() 
     objectB.addData(19)  #Is this a problem or should I stub objectB? 

     assert(functionA(objectB) is False) 

これはPythonですか?私はPythonを知らないのですが、functionAはobjectB.dataが10のときtrueを返し、それ以外のときはfalseを返します。

functionAは、依然としてobjectBのメンバに基づいてtrueまたはfalseを返すだけです。 objectB.dataが得るどのようにそのデータがそうobjectB.data缶、ユニットテストfunctionAの範囲に関連していないと(可能な場合)真ユニットテストを得るためにスタブ/嘲笑されなければなりません。統合テストは別の話です(実際の実装を使用する必要がありますが、あなたの質問は単体テストに固有です)

+0

お返事ありがとうございます!私の主な問題は、関数Aの唯一の目的はクラスBのインスタンスを取得し、それを使って何かを行うことなので、クラスBのスタブを作成することは意味がないと考えていることです。一方、私はクラスBを初期化するために、私はclassB.addData(randomData)のようなことをするので、私は確信していません。そのコードが失敗するとどうなりますか? – Ant

+0

説明なしのdownvoterありがとう – Kritner

+0

したがって、そのコンストラクタを使用してclassBを作成するのではなく、スタブを使用することをお勧めしますか? – Ant

1

私の意見では、単体テストツールボックスの中で最も強力なツールは依存性注入です。 。

オブジェクトを作成する際には、すべてのコラボレータオブジェクトをコンストラクタにインターフェイス参照の形式で渡す必要があります。あなたの場合、テストされるユニットは関数ですが、原則は同じです。関数collaboratorオブジェクトは、同じ方法で渡されます。

テストオブジェクトがインターフェイスを介して他のオブジェクトとしかコラボレーションしない場合は、ユニットテストでモックオブジェクトを渡すことができます。また、google mockのようなフレームワークは、モックを作成するのに非常に便利で、期待されるインタラクションが分かりやすいクリーンなテストケースを作成できます。

これがあなたが意味するものなら、それは良いパターンです。

編集:

これは私がテスト機能を書く方法です。

def functionA(objectB): 
    return objectB.data < 10 

def testFunctionA(): 
     objectB = fakeClassB() 
     EXPECT_CALL(objectB, data).WillOnce(Return(19)) 
     assert(functionA(objectB) is False) 

実際のclassBオブジェクトを渡す代わりに、fakeClassBオブジェクトを渡します。これにより、クラスBの実際の実装ではなく、クラスBのインタフェースに応じてテストが行​​われます。失敗したテストは、インターフェイスの使用が間違っているために発生します。あなたがどの言語で作業しているかによって、これは可能かもしれないし、そうでないかもしれません。

もう1つは、ビルドの複雑さです。 classBの実装を構築せずにテスト関数を構築することができます。あなたはclassBとfakeClassBのインタフェースを構築すればよい。

+0

あなたの答えをありがとう:)この場合、私は関数の唯一の目的はインスタンスをテストすることなので、依存性注入は必要ありません私の質問は、関数Aをテストするとき、クラスBの実際のインスタンスを初期化し(そしてclassB.addData(randomData)のようなものを呼び出す)、クラスAの代わりにスタブを作成して関数Aに渡すべきです? – Ant

0

テストでは、規則:mock all units other than the tested oneがあります。嘲笑のポイントは、testedユニットで使用されているユニットを呼び出すときに、正しい出力値を提供することです。 testedユニットは、使用されているユニットに起因する何らかの不具合によって故障しないように、正確であることがわかっているサンプルを明示的に提供する必要があります。

関連する問題