IFステートメントでの複数の条件の単体テスト


25

次のようなコードの塊があります。

function bool PassesBusinessRules()
{
    bool meetsBusinessRules = false;

    if (PassesBusinessRule1 
         && PassesBusinessRule2
         && PassesBusinessRule3)
    {
         meetsBusinessRules= true;
    }

    return meetsBusinessRules;
}

この特定の機能には、4つのユニットテストがあるはずです。ifステートメントの各条件をテストし、falseを返すことを確認するには3つ。そして、関数がtrueを返すことを確認する別のテスト。

質問:代わりに、実際には10個の単体テストが必要ですか?考えられる各障害パスをチェックする9つ。IE:

  • 偽偽偽
  • False False True
  • False True False

など、可能な組み合わせごとに。

それはやり過ぎだと思いますが、私のチームの他のメンバーの一部はそうではありません。私が見る方法は、BusinessRule1が失敗した場合、常にfalseを返す必要があり、最初にチェックされたか最後にチェックされたかは関係ありません。


コンパイラーは&&演算子に貪欲な評価を使用しますか?
suszterpatt

12
10個の単体テストを作成した場合、メソッドではなく&&演算子をテストすることになります。
メルトアカカヤ

2
考えられるすべての組み合わせをテストした場合、8つのテストしかありませんか?3つのブールパラメータがオンまたはオフになりました。
クリスハーパー

3
@Mert:&&が常に存在することを保証できる場合のみ。
ミスコ

ヒッキー:テストの作成に費やすなら、それは私たちが何か他のことをするのに費やしていない時間です。量と質の両方で結果を最大化するために、私たち一人一人が最善の時間を費やすことを評価する必要があります。テストの作成に時間の50%を費やすことで結果が最大になると人々が思う場合は、大丈夫です。それは私には当てはまらないと思います。むしろ、自分の問題について考える時間を費やしたいと思います。私にとって、これは私の時間の他の用途よりも、より少ない欠陥で、より良い解決策を生み出すと確信しています。完全なテストスイートを備えた不適切なデザインは、依然として不適切なデザインです。
ジョブ

回答:


28

正式には、これらの種類のカバレッジには名前があります。

まず、述語の範囲があります。ifステートメントをtrueにするテストケースと、falseにするテストケースが必要です。このカバレッジが満たされることは、おそらく優れたテストスイートの基本的な要件です。

次に、条件カバレッジ:ifの各サブ条件の値がtrueおよびfalseであることをテストします。これにより明らかにより多くのテストが作成されますが、通常はより多くのバグが検出されるため、時間があればテストスイートに含めることをお勧めします。

最も高度なカバレッジ基準は、通常、組み合わせ条件カバレッジと呼ばれます。ここでの目標は、テスト内のブール値のすべての可能な組み合わせを通過するテストケースを持つことです。

これは、単純な述語または条件カバレッジよりも優れていますか?カバレッジの面では、もちろん。しかし、それは無料ではありません。テストのメンテナンスに非常に高いコストがかかります。このため、ほとんどの人は完全に組み合わせてカバーすることを気にしません。通常、すべてのブランチ(またはすべての条件)をテストすることで、バグをキャッチできます。コンビナトリアルテスト用に追加のテストを追加しても、通常は多くのバグをキャッチすることはできませんが、作成と保守には多大な労力が必要です。余分な労力は通常、非常に小さな見返りに値しないため、これはお勧めしません。

この決定の一部は、そのコードがどれほど危険であると考えるかに基づいているべきです。失敗する余地がたくさんある場合は、テストする価値があります。ある程度安定しており、あまり変わらない場合は、テスト作業を他の場所に集中することを検討する必要があります。


2
ブール値が外部ソースから渡される場合(常に検証されるとは限らないことを意味します)、組み合わせ条件付きカバレッジが必要になることがよくあります。最初に組み合わせの表を作成します。次に、各エントリについて、そのエントリが意味のあるユースケースを表しているかどうかを判断します。そうでない場合は、その組み合わせが実行されないようにするためのコード(ソフトウェアアサーションまたは検証句)が必要です。単一の組み合わせテストですべてのパラメーターをひとまとめにすることは重要ではありません。パラメーターを互いに相互作用する、つまり同じブール式を共有するグループに分割してみてください。
rwong

太字の用語はどの程度確実ですか?あなたの答えは「組み合わせ条件カバレッジ」の唯一の出現であるようであり、いくつかのリソースは「述語カバレッジ」と「条件付きカバレッジ」は同じことだと言っています。
Stijn

8

最終的に、それはあなた(rチーム)、コード、および特定のプロジェクト環境に依存します。普遍的なルールはありません。あなた(rチーム)は、コードが実際に正しいと安心するために必要な数のテストを書くべきです。したがって、チームメイトが4つのテストに納得していない場合は、さらにテストが必要かもしれません。

ユニットのテストを書くOTOHの時間は通常、乏しいリソースです。それで、あなたが持っている限られた時間を過ごす最良の方法を見つけるよう努めてください。たとえば、カバレッジが0%の別の重要なメソッドがある場合、このメソッドに追加のテストを追加するよりも、そのテストをカバーする単体テストをいくつか記述する方がよい場合があります。もちろん、それぞれの実装の脆弱性にも依存します。近い将来、この特定の方法に多くの変更を計画すると、追加のユニットテストの範囲が正当化される可能性があります。したがって、プログラム内のクリティカルパス上にある可能性があります。これらはすべて、あなた(rチーム)だけが評価できる要因です。

私は通常、あなたが概説する4つのテストに満足しています。

  • true false false
  • false true false
  • false false true
  • true true true

プラス多分:

  • true true false

の戻り値を取得する唯一の方法がtrue3つのビジネスルールすべてを満たすことを確実にするため。しかし、最終的に、チームメイトがコンビナトリアルパスをカバーすることを主張する場合、引数をさらに長く続けるよりも、これらの追加のテストを追加する方が安くなる場合があります:-)


3

安全にしたい場合は、3変数の真理値表(http://teach.valdosta.edu/plmoch/MATH4161/Spring%202004/and_or_if_files/image006.gif)で表される条件を使用した8つの単体テストが必要になります。

チェックがその順序で実行されることをビジネスロジックが常に規定していることを確信することはできません。また、テストで実際の実装について可能な限り知る必要はありません。


2
単体テストホワイトボックステストです。
ペテルトレック

まあ順序は問題ではないはず、&& communitiveである、または少なくともでなければなりません
ザカリーK

2

はい、理想的な世界には完全な組み合わせが必要です。

単体テストを行うときは、メソッドがどのように機能するを実際に無視するようにしてください。3つの入力を提供し、出力が正しいことを確認するだけです。


1
単体テストホワイトボックステストです。そして、私たちは理想的な世界に住んでいません。
ペテルトレック

@PéterTörök-確かに理想的な世界に住んでいるわけではありませんが、スタック交換は他の点であなたに同意しません。特にTDDの場合、テストは実装ではなく仕様に書かれています。私は個人的にすべての入力(メンバー変数を含む)とすべての出力(副作用を含む)を含めるために「仕様」を取ります。
テラスティン

1
StackOverflowの特定の1つのスレッドにすぎません。特定のケースについては、一般化すべきではありません。特に、この現在の投稿は明らかに、すでに記述されているコードのテストに関するものです。
ペテルトレック

1

国家は悪です。次の関数は、副作用がなく、何をするのか、何をしないのかがよく理解されているため、単体テストは必要ありません。なぜテストするのですか?あなた自身の脳を信頼しませんか???静的関数は素晴らしいです!

static function bool Foo(bool a, bool b, bool c)
{
    return a && b && c;
}

2
いいえ、私は自分の脳を信頼していません-私は自分がやっていることを常に二重チェックする難しい方法を学びました:-)将来コードを壊すために。より単体テストは、によって表される状態を算出する発信者の方法を確認しabそしてc。ビジネスロジックは自由に動かすことができますが、最終的にはどこかでテストする必要があります。
ペテルトレック

@PéterTörök、テストでタイプミスをすることもできます。その結果、誤検知が発生する可能性があります。単体テスト用の単体テストを作成していますか?私も自分の脳を100%信頼していませんが、結局のところ、コードを書くことは私が生計を立てていることです。この関数内にバグがある可能性がありますが、バグをソースに簡単にトレースできるようにコードを記述することが重要です。そのため、問題を切り分けて修正した後は、 。よく書かれたコードは、統合テスト主に頼ることができるinfoq.com/presentations/Simple-Made-Easy
仕事を

2
実際、テストにも欠陥があります。(TDDは、テストを最初に失敗させることでこれを解決します。)ただし、同じ種類のエラーを2回(および見落とし)することは、はるかに低い確率です。一般に、ソフトウェアにバグがないことを証明できるテストの量と種類はありません。バグの可能性を許容レベルまで下げるだけです。また、ソースへのバグのトレース速度では、IMOは単体テストに勝るものはありません-高速フィードバックルール:-)
ペーテルTörök

「次の関数は単体テストを必要としません」あなたはここで皮肉をこめていると思いますが、それは明確ではありません。自分の脳を信頼しますか?いや!コードに触れる次の人の脳を信頼しますか?さらにもっと!コードの背後にあるすべての仮定が今から1年後に真実になると信じていますか?...私のドリフトを取得します。また、FPを実行する場合は、静的関数がOOを強制終了し、FP言語を使用します。
ロブ14

1

この質問はかなり古いものです。しかし、私は問題に別の視点を与えたいです。

まず、ユニットテストには2つの目的があります。

  1. あなたとあなたのチームメイトのためにドキュメントを作成してください。そうすることで、一定時間後にユニットテストを読み、あなたが理解しwhat's the class' intentionhow the class is doing its work
  2. 開発中、ユニットテストは、書き留めているコードが意図したとおりに動作していることを確認します。

そのため、問題を再現して、aをテストcomplex if statementします。与えられた例では、2 ^ 3の可能性があります。これは、書くことができるテストの重要な量です。

  • この事実に適応して、8つのテストを書き留めるか、パラメーター化されたテストを使用できます。
  • また、他の回答に従うこともできます。テストは意図的に明確にする必要があることを覚えておいてください。この方法では、近い将来、理解しにくくなるような詳細な情報を混乱させることはありません。 what is doing the code

一方、テストが実装よりもさらに複雑であるという立場にある場合、テスト自体ではなく実装を(場合によっては多少)再設計する必要があるためです。

たとえば、複雑なifステートメントの場合、チェーンの責任パターンについて考えることができます、各ハンドラーを次のように実装。

If some simple business rule apply, derive to the next handler

複雑なルールの代わりに、いくつかの単純なルールをテストするのはどれほど簡単でしょうか?

それが役に立てば幸い、


0

これは、quickcheck(http://en.wikipedia.org/wiki/QuickCheck)のようなものがあなたの友人になるケースの1つです。N個すべてのケースを手動で書き出す代わりに、コンピューターにすべての(または少なくとも多数の)可能なテストケースを生成させ、すべてが適切な結果を返すことを検証します。

ここで生計を立てるためにコンピューターをプログラムしています。コンピューターをプログラムして、テストケースを生成してみませんか。


0

条件をガード条件にリファクタリングできます。

if (! PassesBusinessRule1) {
    return false;
}

if (! PassesBusinessRule2) {
    return false;
}

if (! PassesBusinessRule3) {
    return false;
}

私はそれがケースの数を減らすとは思わないが、私の経験では、このようにケースを分けるほうが簡単だと思う。

(私は「単一出口」の大ファンですが、ガード条件については例外を設けていますが、コードを構造化して他のリターンを持たない方法があります。)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.