2017-08-12 3 views
2

あなたは3つの機能、関数A、関数B、およびfunctionCユニット..

を持っfunctionCが

functionA(a) { 
    return a 
} 
functionB(b) { 
    return b 
} 
functionC(a, b){ 
    return functionA(a) + functionB(b); 
} 

関数Aと関数Bに依存している今、これは明らかに、超簡単な例であると言うの複合機能をテストするが、何が正しいのですfunctionCをテストする方法は?私が既にfunctionAとfunctionBをテストしていて、それを渡すことはfunctionCのテストではないでしょう。functionAとfunctionBが返されるので、単体テスト以上のテストになります。

+0

は今まであなたがしている任意の関数あります*他の関数を呼び出さない*標準的なライブラリ関数であっても?それ自体が基準ではありません。 – deceze

+0

あなたはまだ何か答えを受け入れていないことに気付きました。そうすることを検討してください...私の答えが合格になるようにするために追加できるものがあれば教えてください。 – GhostCat

答えて

4

最初の2つの関数については、パブリック・コントラクト - 異なるケースのすべての結果が期待どおりになることを保証するために必要な数のテストを作成します。

しかし、3番目の関数では、関数が他の2つの関数を呼び出す必要があることを理解するだけで十分です。だから、必要なテストはもっと少なくて済むでしょう。 AとBのテストに必要なすべてのケースを再度テストする必要はありません.Cが責任を負うことになっている "配管"を確認したいだけです。

+0

短くて細かい答えが常により良い:) – davidxxx

4

あなたのテストでは、はわかりません functionCはfunctionAとfunctionBを使用しています。通常、変更をサポートする自動テストを作成します(コード保守)。 Cの実装を変更するとどうなりますか? functionCのすべてのテストも同様に無効になります。これは不要で危険です。リファクタントはすべてのテストも理解する必要があるためです。たとえ彼が確信していても、彼/彼女は契約を変更していません。あなたが素晴らしいテストカバレッジを持っているなら、なぜ彼/彼女はそれを行うべきですか?したがって、functionCの公開契約は完全にテストされます!

さらに、テストではsut(functionC)の内部動作についてあまりにも多くのことを知っていれば、内部でコードを再実装する傾向があります。したがって、実装を行う同じ(多分欠陥のある)コードは、実装が正しいかどうかをチェックします。 例:functionCの(ホワイトボックス)テストをどのように実装しますか?モックfunctionAとfunctionBをモックし、モックされた結果の合計が生成されるかどうかを調べる。それはテストカバレッジ(kpi ??)には効果的ですが、かなり誤解を招く可能性もあります。

しかし、functionAとfunctionBの機能性を2回テストしてみると、どうしてでしょうか?余分な努力そうであれば、おそらくテストコードの再利用は容易に可能です。再利用が不可能な場合は、私の初期のステートメントを確認してください。

+0

functionAが副作用(データベース更新など)を持つ別の関数を呼び出すとどうなるでしょうか? functionCをテストするとき、副作用を持つa-treeの最後の機能をスタブしますか?その場合、functionAを使用するすべてのテスト済み関数で繰り返す必要がありますか?または、functionAをスタブして副作用を避けるためにモックを返しますか? – henit

+0

@henit私は副作用を避けることはできませんが、それもチェックしてください。各テストは、空のdb、または少なくとも同じdb-stateから開始する必要があります。さもなければ、点滅試験が期待される。これはテストインフラストラクチャの一部でなければなりません。 – aschoerk

+0

副作用がテストアーキテクチャの外部にある場合はどうなりますか?外部apiへのhttp呼び出しのように – henit

1

GhostCatの回答は、シンプルで上質で、必須事項に焦点を当てています。
私は、特にリファクタリングに関する質問を考慮する必要がある点について詳しく説明します。


単体テストはAPI

クラスのAPI(パブリック関数)に焦点を当ててユニットをテストする必要があります。
これら3つの機能が公開されている場合、それぞれの機能をテストする必要があります。

さらに、単体テストは実装に集中するのではなく、期待される動作に焦点を合わせます。
今日、複合関数は個々の関数の結果を追加します。明示的には、それらを引くことができます。
C()複合関数をテストしても、A()B()のすべてのシナリオを再度テストするという意味ではなく、C()の予想される動作をテストすることを意味します。

個々の関数との統合で複合関数をテストするユニットでは、個々の関数に関して多くの重複が生成されないことがあります。
それ以外の場合もあります。私は次の点でそれを提示します。 C()複合機能をテストするテストにおける複製の問題を引き起こす可能性が


例。

A()関数は2つの整数受け入れることとします

function A(int a, int b){ ...} 

をそれが入力パラメータについて次の制約があります。

  • 彼らは彼らがしている> = 0
  • でなければなりません100より劣っている
  • 合計が100より劣っている

これらのいずれかが尊重されない場合、例外がスローされます。 A()ユニットテストでは、これらのシナリオのそれぞれをテストします。おそらく、明確なテストケース内の各1:脇

@Test 
void A_throws_exception_when_one_of_params_is_not_superior_or_equal_to_0(){ 
    ... 
} 

@Test(expected = InvalidParamException.class); 
void A_throws_exception_when_one_of_params_is_not_inferior_to_100(){ 
    ... 
} 

@Test(expected = InvalidParamException.class); 
void A_throws_exception_when_params_sum_is_not_inferior_to_100(){ 
    ... 
} 

エラーケースは、我々はまた、A()機能のために複数の名目上のシナリオは、渡されたパラメータに応じて可能性があります。

B()関数に複数の公称シナリオとエラーシナリオがあるとします。

C()のユニットテストでは、それらを集約しますか?
もちろん、これらのケースのそれぞれを再テストしないでください。それは重複しているだけでなく、2つの機能のケースを交差させることでより多くの組み合わせを持つことになります。
次の点は、重複を防ぐ方法です。


可能なリファクタリングあなたが複合機能を書いている、あなたは不思議最初にすべきことは、複合機能をすべきかどうかである設計を改善し、複合機能

のユニットテストでの重複を減らすために特定のコンポーネントには配置しないでください。

composite component -> unitary component(s) 

これらをデカップリングすると、全体的なデザインが改善され、コンポーネントに対してより具体的な責任が与えられる可能性があります。
さらに、複合コンポーネントのユニットテストで重複を減らすための自然な方法も提供します。
実際、必要に応じて、スタブ/モックの単一コンポーネント動作を行うことができ、詳細なフィクスチャを作成する必要はありません。
コンポジットコンポーネント単体テストは、コンポジットコンポーネントの動作に重点を置くことができます。

だから、私たちの前の例では、代わりに私たちのユニットテストC()関数としてA()B()のすべてのケースをテストするのは、我々はC()のシナリオで期待どおりに動作の順にA()B()スタブやモックができます。

例えばA()B()に関連するエラーケースとC()テストシナリオのために、私たちは各A()またはB()シナリオの例を繰り返す必要はありません。

@Test(expected = InvalidParamException.class); 
void C_throws_exception_when_a_param_is_invalid(){ 
    when(A(any,any)).thenThrow(new InvalidParamException()); 
    C(); 
} 

@Test(expected = InvalidParamException.class); 
void C_throws_exception_when_b_param_is_invalid(){ 
    when(B(any,any)).thenThrow(new InvalidParamException()); 
    C(); 
} 
+0

長時間の回答も問題ありません。すべては著者に依存しています:-) – GhostCat

+0

@GhostCat Right :)私はあなたの最近の歴史を見て、この古い質問につきものです。とても興味深い !追加するものを残していただきありがとうございます:) – davidxxx