29

単体テストで最大限のコード カバレッジを実行するのは良いことだということを常に学びました。また、Microsoft などの大企業の開発者は、実行コード自体よりも多くの行のテスト コードを記述すると言っているのも耳にします。

さて、それは本当に素晴らしいですか?メンテナンスをより困難にするだけの影響を与える完全な時間の損失のように思われることはありませんか?

たとえばDisplayBooks()、データベースから本のリストを生成するメソッドがあるとします。製品の要件では、ストアに 100 冊以上の本がある場合、100 冊のみを表示する必要があることが示されています

したがって、TDD では、

  1. BooksLimit()データベースに 200 冊の本を保存し、 を呼び出しDisplayBooks()、 を実行する単体テストを作成することから始めますAssert.AreEqual(100, DisplayedBooks.Count)
  2. 次に、失敗するかどうかをテストします。
  3. 次にDisplayBooks()、結果の制限を 100 に設定して変更します。
  4. 最後に、テストを再実行して、成功するかどうかを確認します。

BooksLimit()では、直接 3 番目のステップに進み、単体テストをまったく行わない方がはるかに簡単ではないでしょうか。そして、要件が 100 冊から 200 冊の制限に変更される場合、テストを変更し、テストを実行して失敗するかどうかを確認し、コードを変更して、テストを再度実行して成功するかどうかを確認する代わりに、1 文字だけを変更する方がアジャイルではありませんか?

注: コードが完全に文書化されていると仮定しましょう。それ以外の場合は、完全な単体テストを実行すると、ドキュメントが不足しているコードを理解するのに役立つと言う人もいますが、それは正しいでしょう。実際、BooksLimit()単体テストを行うと、表示する書籍の最大数があり、この最大数が 100 であることが非常に明確に示されます。非単体テストのコードにステップインすることは、はるかに困難です。for (int bookIndex = 0; bookIndex < 100; ...または実装されていますforeach ... if (count >= 100) break;

4

8 に答える 8

34

さて、3番目のステップに直接進む方がはるかに簡単ではなく、BooksLimit()の単体テストをまったく行わないでください。

はい...テストの作成に時間を費やさなければ、テストの作成に費やす時間が少なくなります。デバッグに多くの時間を費やすため、プロジェクト全体に時間がかかる可能性がありますが、マネージャーに説明する方が簡単かもしれません。もしそうなら...新しい仕事を手に入れよう!ソフトウェアに対する信頼を高めるには、テストが不可欠です。

単体テストは、コードが多い場合に最大の価値をもたらします。ユニットテストを行わなくても、いくつかのクラスを使用して簡単な宿題を簡単にデバッグできます。世界に出て、数百万行のコードベースで作業していると、それが必要になります。デバッガーをすべてのステップで実行することはできません。あなたは単にすべてを理解することはできません。あなたはあなたが仕事に依存しているクラスを知る必要があります。誰かが「私はこの振る舞いにこの変更を加えるつもりです...私はそれが必要だからです」と言うかどうかを知る必要がありますが、彼らはその振る舞いに依存する他の200の用途があることを忘れています。ユニットテストはそれを防ぐのに役立ちます。

メンテナンスを難しくすることに関して:まさか! 私はそれを十分に活用することができません。

あなたがあなたのプロジェクトに取り組んだ唯一の人なら、そうです、あなたはそう思うかもしれません。しかし、それはクレイジーな話です!ユニットテストなしで30kラインプロジェクトのスピードを上げてみてください。単体テストなしでコードに大幅な変更を必要とする機能を追加してみてください。自信がない他のエンジニアによる暗黙の仮定を破っていないこと。メンテナ(または既存のプロジェクトの新しい開発者)にとって、単体テストが重要です。私は、ドキュメンテーション、振る舞い、仮定、何かを壊したときのことを教えてくれるユニットテストに頼ってきました(私は無関係だと思っていました)。APIの記述が不十分な場合、テストの記述が不十分であり、テストが常に無駄になるため、変更するのが悪夢になることがあります。最終的には、このコードをリファクタリングして修正したいと思うでしょうが、ユーザーもそれを感謝します。そのため、APIははるかに使いやすくなります。

カバレッジに関する注記:

私にとって、それは約100%のテストカバレッジではありません。100%のカバレッジではすべてのバグが検出されるわけではありません。次の、2つのifステートメントを持つ関数について考えてみます。

// Will return a number less than or equal to 3
int Bar(bool cond1, bool cond2) {
  int b;
  if (cond1) {
    b++;
  } else {
    b+=2;
  }

  if (cond2) {
    b+=2;
  } else {
    b++;
  }
}

ここで、次のテストを行うテストを作成することを検討してください。

EXPECT_EQ(3, Bar(true, true));
EXPECT_EQ(3, Bar(false, false));

それは100%のカバレッジです。これも契約を満たさない関数ですBar(false, true);。4を返すため失敗します。したがって、「完全なカバレッジ」は最終目標ではありません。

正直なところ、私はのテストをスキップしますBooksLimit()。定数を返すので、それらを書くのに時間をかける価値はないでしょう(そして書くときにテストする必要がありますDisplayBooks())。誰かが棚のサイズからその制限を(誤って)計算することを決定し、それがもはや私たちの要件を満たさなくなったとき、私は悲しいかもしれません。私は以前に「テストする価値がない」ことでやけどを負ったことがあります。昨年、同僚に「このクラスはほとんどデータであり、テストする必要はありません」と言ったコードを書きました。方法がありました。バグがありました。それは生産に行きました。それは真夜中に私たちを呼び出しました。私は愚かでした。だから私はテストを書きました。そして、私は、どのコードが「テストする価値がない」と構成されているかについて、長く懸命に考えました。あまりありません。

したがって、はい、いくつかのテストをスキップできます。100%のテストカバレッジは素晴らしいですが、それはあなたのソフトウェアが完璧であることを魔法のように意味するものではありません。それはすべて、変化に直面したときの自信に帰着します。

をまとめて、うまくいかないものを見つけた場合、class A3つすべてのデバッグに時間を費やしたいですか?いいえ。私はそれを知りたいのですが、すでに(ユニットテストを介して)彼らの契約を満たしていて、私の新しいコードはおそらく壊れています。だから私はそれをユニットテストします。ユニットテストを行わないと、壊れていることをどうやって知ることができますか?いくつかのボタンをクリックして新しいコードを試してみませんか?それは良いことですが、十分ではありません。プログラムがスケールアップすると、すべての手動テストを再実行して、すべてが正しく機能することを確認することはできなくなります。そのため、単体テストを行う人は通常、テストの実行も自動化します。「合格」または「不合格」と言ってください。「出力は...」とは言わないでください。class Bclass CABclass C

OK、もう少しテストを書いてみよう...

于 2010-06-26T12:23:32.827 に答える
11

100% の単体テスト カバレッジは通常、コードの臭いです。これは、誰かがより有用なことを行うのではなく、カバレッジ ツールの緑色のバーを超えてすべての OCD に到達したことを示しています。

約 85% がスイート スポットであり、コメント マーカー内ではないテキストの変更の避けられない結果ではなく、実際の問題または潜在的な問題を示していないテストの失敗がより頻繁に発生します。あなたの仮定が「コードはそれが何であるかであり、それが何らかの形で異なっていれば、それは何か他のものになるだろう」である場合、コードに関する有用な仮定を文書化していません。これは、単体テストではなく、コメント対応のチェックサム ツールによって解決される問題です。

ターゲット カバレッジを指定できるツールがあればいいのにと思います。そして、誤ってそれを超えてしまった場合は、黄色/オレンジ/赤で物事を表示して、偽の余分なテストのいくつかを削除するように促します.

于 2010-06-26T13:14:38.840 に答える
6

孤立した問題を見るとき、あなたは完全に正しいです。ただし、単体テストは、特定のコード部分に対するすべての意図を網羅するものです。

基本的に、単体テストは意図を定式化します。意図の数が増えると、テスト対象のコードの動作は、これまでに作成されたすべての意図に対して常にチェックできます。変更が加えられるたびに、既存の意図を壊す副作用がないことを証明できます。新たに発見されたバグは、コードによって保持されていない (暗黙の) 意図に他ならないため、意図を新しいテスト (最初は失敗) として策定し、それを修正します。

1 回限りのコードの場合、大幅な変更は想定されていないため、単体テストを行う価値はありません。ただし、維持する必要がある、または他のコードのコンポーネントとして機能するコードのブロックについては、すべての意図が新しいバージョンに対して保持されることを保証することは、多くの価値があります (手動で副作用をチェックしようとする労力が少なくなるという点で)。 .

単体テストが実際に時間とお金を節約する転換点は、コードの複雑さによって異なりますが、通常は変更を数回繰り返しただけで到達する転換点が常にあります。また、重要なことを言い忘れましたが、製品の品質を損なうことなく、修正や変更をはるかに迅速に出荷できます。

于 2010-06-26T12:05:06.733 に答える
5

コードカバレッジと優れたソフトウェアの間に明確な関係はありません。100%(または近い)コードカバレッジを持ち、それでも多くのバグが含まれているコードの一部を簡単に想像できます。(これはテストが悪いという意味ではありません!)

「テストをまったく行わない」アプローチの敏捷性についてのあなたの質問は、短い視点でのみ良い質問です(つまり、プログラムをより長い時間構築することを計画している場合、それはおそらく良くないことを意味します)。私の経験から、このような単純なテストは、プロジェクトがどんどん大きくなり、ある段階で大幅な変更を加える必要がある場合に非常に役立つことがわかっています。これは、あなたが自分自身に言うときの瞬間かもしれません'私が今紹介したバグを見つけたその小さなテストを書くために少し余分な時間を費やすのは良い決断でした

私は最近コードカバレッジの大ファンでしたが、今では(幸運にも)「問題カバレッジ」アプローチのようなものに変わりました。これは、 「コード行」だけでなく、発見されたすべての問題とバグをテストでカバーする必要があることを意味します。「コードカバレッジレース」を行う必要はありません。

「アジャイル」という言葉は、「100%のカバレッジ」や「テストがまったくない」ではなく、「優れたソフトウェアを構築し、不要なコードを書くのに時間を無駄にしないのに役立つテストの数」として理解しています。それは非常に主観的であり、あなたの経験、チーム、テクノロジー、および他の多くの要因に基づいています。

「100%コードカバレッジ」の心理的な副作用は、コードにバグがないと思うかもしれないということです。これは決して真実ではありません:)

于 2010-06-26T12:17:42.773 に答える
2

@soru に同意します。100% のテスト カバレッジは合理的な目標ではありません。

「正しい」カバレッジの量を教えてくれるツールや指標が存在するとは思えません。私が大学院にいたとき、論文指導教官の仕事は、「変異した」コードのテスト カバレッジの設計でした。彼は一連のテストを行い、自動化されたプログラムを実行して、テスト対象のソース コードにエラーを作成します。変更されたコードには現実世界で見つかるエラーが含まれているため、壊れたコードの割合が最も高いテスト スイートが勝者であるという考えでした。

彼の論文は受理され、現在は主要な工学部の教授になっていますが、次のいずれも見つかりませんでした。

1) 最適なテスト カバレッジのマジック ナンバー 2) 100% のエラーを検出できる任意のスイート。

目標は、100% のカバレッジを見つけることではなく、100% のエラーを見つけることです。

@soru の 85% が正しいかどうかは、議論の対象です。より良い数値が 80% なのか 90% なのか、それ以外なのかを評価する手段がありません。しかし、実際の評価としては、85% が私にとって正しいと感じています。

于 2010-06-27T04:00:37.607 に答える
1

特に大きなプロジェクトでは、最初の 100% を取得するのは困難です。コードのブロックがカバーされているときに行ったとしても、テストがすべての可能な入力と出力をアサートしていない限り、それが想定されていることを行っていることを意味するわけではありません(これはほとんど不可能です)。

したがって、コード カバレッジが 100% であるという理由だけでソフトウェアが優れているとは考えませんが、コード カバレッジは依然として優れています。

さて、3 番目のステップに直接進み、BooksLimit() の単体テストをまったく行わない方がはるかに簡単ではないでしょうか?

そのテストがあると、誰かがコードを変更してテストが失敗した場合に、新しいコードに何か問題があることに気付くので、アプリケーションの潜在的なバグを回避できるという確信が持てます。

于 2010-06-26T13:25:12.407 に答える
0

クライアントが制限を 200 に変更することを決定した場合、その一見些細なテストに関連するバグを見つけることができれば幸いです。特に、コードに他の 100 個の変数があり、その小さな情報に依存するコードに取り組んでいる開発者が他に 5 人いる場合です。

私の言いたいことは、それがビジネス価値にとって価値がある場合 (または、名前が気に入らない場合は、プロジェクトの非常に重要なコアにとって価値がある場合)、それをテストすることです。UI やユーザー インタラクションなど、可能な (または安価な) テスト方法がない場合、またはそのテストを記述しないことによる影響が最小限であることが確実な場合にのみ、破棄してください。これは、漠然とした、または急速に変化する要件を持つプロジェクトに当てはまります [私が痛々しいほど発見したように]。

あなたが提示する他の例では、境界値をテストすることをお勧めします。したがって、テストを 4 つの値のみに制限できます: 0、0 と BooksLimit の間の魔法の数、BooksLimit、およびそれ以上の数です。

そして、他の人が言ったように、テストを行いますが、他の何かが失敗する可能性があることを 100% ポジティブに考えてください。

于 2010-06-27T04:23:54.280 に答える