web-dev-qa-db-ja.com

単体テストでの開発とテストなしの開発の時間差

私は、要件、緊急度、またはその両方に応じて、開発期間がプロジェクトごとに通常1〜4週間の範囲である、かなり時間に制約のある作業環境を持つソロ開発者です。私はいつでも3〜4のプロジェクトを扱っていますが、いくつかは互いに重複するタイムラインを持っています。

予想どおり、コードの品質が低下します。また、正式なテストも受けていません。それは通常、いくらか壊れるまでシステムを歩くことになります。その結果、かなりの量のバグが本番環境にエスケープされ、私はそれを修正する必要があり、他のプロジェクトを後退させます。

これがユニットテストの出番です。正しく行われると、本番環境に脱出するバグはもちろんのこと、バグも最小限に抑えられます。一方、テストの作成にはかなりの時間がかかる可能性があります。これは、私のような時間に制約のあるプロジェクトには適していません。

問題は、テストされていないコードに対してユニットテストされたコードを作成するのにどのくらいの時間差があり、プロジェクトの範囲が拡大するにつれて、その時間差はどのように拡大するのでしょうか?

135
Revenant

テストが遅いほど、テストの作成にかかるコストが高くなります。

バグの存続期間が長くなるほど、修正に費用がかかります。

リターンの減少の法則により、バグがないことを確認しようとする忘却に自分自身をテストすることができます。

仏は中道の知恵を教えました。テストは良いです。良いことは多すぎるというようなものがあります。重要なのは、あなたがいつバランスが崩れているかを知ることができることです。

テストなしで作成するコードのすべての行は、コードを作成する前にテストを作成した場合よりも、後でテストを追加する場合のコストが大幅に高くなります。

テストのないコードのすべての行は、デバッグまたは書き換えが著しく困難になります。

あなたが書くすべてのテストには時間がかかります。

すべてのバグを修正するには時間がかかります。

忠実な人は、最初に失敗するテストを書かずに1行のコードを書かないように指示します。テストでは、期待どおりの動作が得られていることを確認します。テストでは動作が同じであることを証明しているため、システムの他の部分に影響を与えることを心配することなく、コードをすばやく変更できます。

テストでは機能が追加されないという事実に対して、これらすべてを比較検討する必要があります。量産コードは機能を追加します。そして、機能は、請求書を支払うものです。

実用的に言えば、回避できるすべてのテストを追加します。私はテストを見ることを支持するコメントを無視します。私はコードが私が思っていることをするのを信用していません。私はテストを信頼しています。しかし、私はときどきあられメアリーを投げて幸運になることで知られています。

ただし、成功した多くのコーダーはTDDを行いません。それは彼らがテストしないという意味ではありません。彼らは、コードのすべての行がそれに対して自動化されたテストを持っていると強迫的に主張しません。ボブおじさんでさえ、UIをテストしていないことを認めています。彼はまた、UIからすべてのロジックを移動することを要求しています。

フットボールのメタファー(それはアメリカンフットボールです)として、TDDは良いグラウンドゲームです。あなたがコードの山を書いて、それが機能することを望んでいる手動のみのテストは合格ゲームです。どちらでも得意です。あなたが両方を行うことができない限り、あなたのキャリアはプレーオフを作るつもりはありません。それぞれをいつ選ぶかを学ぶまで、スーパーボウルは作成されません。しかし、あなたが特定の方向にナッジを必要とするならば、私が通り過ぎるとき、当局の呼びかけはより頻繁に私に反対します。

TDDを試してみたい場合は、職場で試す前に練習することを強くお勧めします。 TDDは、半分の方法で、半分の心で、半分の評価で行われたことが、一部の人がそれを尊重しない大きな理由です。 1杯の水を別のグラスに注ぐようなものです。コミットせずにすばやく完全に実行すると、テーブル全体に水が滴り落ちます。

148
candied_orange

私は残りの回答に同意しますが、時間差は何であるかの質問に直接回答します。

Roy Osherove 彼の本の中で The Art of Unit Testing、Second Edition 200ページは、2つの異なるクライアントに対して同様のチーム(スキルに関して)で同様のサイズのプロジェクトを実装するケーススタディを行いました一方のチームはテストを行いましたが、もう一方のチームは行いませんでした。

彼の結果はそのようなものでした:

Team progress and output measured with and without tests

したがって、プロジェクトの最後には、時間とバグの両方が少なくなります。もちろん、これはプロジェクトの規模によって異なります。

112
Aki K

1つだけ研究があり、「現実世界の設定」でこれを研究したのは、次のうちどれですか。 テスト駆動開発による品質向上の実現:4つの産業チームの結果と経験 。これは基本的に、同じソフトウェアを同じようなチームで2回(理想的にはさらに頻繁に)開発し、1つを除いてすべて捨てる必要があることを意味するため、賢明な方法でこれを行うにはコストがかかります。

調査の結果、開発時間は15%〜35%増加し(TDDの批評家からよく引用される2倍の数値にはなりません)、リリース前の欠陥密度が40%〜90%に減少しました(! )。すべてのチームにはTDDの経験がなかったため、時間の増加は少なくとも部分的には学習に起因している可能性があり、時間の経過とともにさらに減少すると考えられますが、これは調査では評価されていません。

この調査はTDDに関するものであり、あなたの質問はユニットテストに関するものであることに注意してください。これらは非常に異なるものですが、私が見つけることができる最も近いものです。

30
Jörg W Mittag

うまくいったら、単体テストでの開発は、補足されたバグの利点を考慮しなくてもより速くなる可能性があります。

実際のところ、コードがコンパイルされるとすぐにコードを機能させるだけのコーダーではありません。コードを記述/変更するときは、コードを実行して、思ったとおりに機能することを確認する必要があります。あるプロジェクトでは、これは次のようになる傾向がありました。

  1. コードを変更する
  2. アプリケーションをコンパイルする
  3. アプリケーションを実行する
  4. アプリケーションにログイン
  5. ウィンドウを開く
  6. そのウィンドウからアイテムを選択して別のウィンドウを開く
  7. そのウィンドウでいくつかのコントロールを設定し、ボタンをクリックします

そしてもちろん、結局のところ、実際に正しく機能させるには、通常、数回のラウンドトリップが必要でした。

では、単体テストを使用している場合はどうなりますか?その後、プロセスは次のようになります。

  1. テストを書く
  2. テストを実行し、期待どおりに失敗することを確認します
  3. コードを書く
  4. もう一度テストを実行し、合格することを確認します

これは、アプリケーションを手動でテストするよりも簡単で高速です。私はまだアプリケーションを手動で実行する必要があります(そのため、実際にまったく機能しない仕事を提出してもばかげて見えません)が、ほとんどの場合、すでに問題が解決されています。その時点で確認します。保存するときにテストを自動的に再実行するプログラムを使用して、実際には通常、このループをさらに厳密にします。

ただし、これはテストに適したコードベースでの作業に依存します。多くのプロジェクトは、多くのテストがあるプロジェクトであっても、テストの作成を困難にします。しかし、それで作業する場合は、手動テストよりも自動テストを介してテストする方が簡単なコードベースを使用できます。おまけとして、自動化されたテストを維持し、回帰を防ぐためにそれらを実行し続けることができます。

24
Winston Ewert

すでにたくさんの回答がありますが、それらは幾分反復的であり、私は別のタックを取りたいと思います。ユニットテストは価値があります。場合に限り、それらは増加しますビジネス価値。テストのためのテスト(簡単なテストまたはトートロジーテスト)、または任意のメトリック(コードカバレッジなど)にヒットするテストは、カーゴカルトプログラミングです。

テストは、作成にかかる時間だけでなく、メンテナンスにもコストがかかります。彼らは彼らがテストするコードとの同期を保つ必要があり、そうでなければ彼らは価値がありません。すべての変更でそれらを実行する時間コストは言うまでもありません。これは取引を壊すものではありません(または本当に必要なものを実行しない言い訳)はありませんが、費用便益分析に組み込む必要があります。

したがって、関数/メソッドをテストするかどうか(またはどのような種類か)を決定するときに尋ねる質問は、「このテストで作成/保護しているエンドユーザーの値は何か?」あなたがその質問に答えられない場合、頭の上から離れて、そのテストはおそらく、執筆/保守のコストに見合わないでしょう。 (または、waaaayテストの欠如よりも大きな問題である問題ドメインを理解していません)。

http://rbcs-us.com/documents/Why-Most-Unit-Testing-is-Waste.pdf

21
Jared Smith

それは、人や、作業しているコードの複雑さと形に依存します。

私にとって、ほとんどのプロジェクトでは、単体テストを作成することで、作業を約25%高速化できます。はい、テストを書く時間も含みます。

問題は、コードを記述したときにソフトウェアがdoneでないことです。それはあなたが顧客にそれを出荷し、彼らがそれに満足しているときに行われます。単体テストは、ほとんどのバグをキャッチし、デバッグのためにほとんどのバグを分離し、コードが優れているという確信を得るために、私が知る限り最も効率的な方法です。あなたはそれらのことを行う必要がありますとにかくなので、それらをうまく行います。

9
Telastyn

問題は、テストされていないコードに対してユニットテストされたコードを作成するのにどのくらいの時間差があり、プロジェクトの範囲が拡大するにつれて、その時間差はどのように拡大するのでしょうか?

プロジェクトの年齢が上がるにつれて問題は悪化します。新しい機能を追加したり、既存の実装をリファクタリングしたりするときはいつでも、以前にテストしたものを再テストして、機能することを確認する必要があるためです。したがって、長期間(複数年)のプロジェクトでは、機能をテストするだけでなく、100回以上再テストする必要がある場合があります。このため、automatedテストを行うとメリットがある場合があります。ただし、IMOは、自動化された単体テストではなく、自動化されたシステムテストであれば十分(またはさらに優れています)です。

2番目の問題は、バグが早期に発見されないと、バグを見つけて修正することが難しくなる可能性があることです。たとえば、システムにバグがあり、最新の変更を行う前にシステムが完全に機能していたことがわかっている場合は、最新の変更に集中して、バグがどのように発生したかを確認します。ただし、最新の変更を行う前にシステムが機能していたことがわからない場合(最新の変更前にシステムが適切にテストされていなかったため)、バグはどこにでもある可能性があります。

上記は特に深いコードに適用され、浅いコードには適用されません。新しいページが既存のページに影響を与える可能性が低い場所に新しいWebページを追加する。

その結果、かなりの量のバグが本番環境にエスケープされ、私はそれを修正する必要があり、他のプロジェクトを後退させます。

私の経験ではそれは受け入れられないので、あなたは間違った質問をしています。テストによって開発が速くなるかどうかを尋ねる代わりに、何が開発をバグのないものにするかを尋ねるべきです。

よりよい質問は次のとおりです。

  • ユニットテストは適切な種類のテストであり、作成している「かなりの量のバグ」を回避する必要がありますか?
  • 同様に、または代わりに、推奨される他の品質管理/改善メカニズム(単体テスト以外)はありますか?

学習は2段階のプロセスです。それを十分に行う方法を学び、次にそれをより迅速に行う方法を学びます。

4
ChrisW

TDDやその他のテスト方法論を宣伝するプログラマーボードには長い歴史があります。私は彼らの主張を思い出したり、それに同意したりすることはしませんが、少し微妙な違いがあるはずです。

  • 状況によっては、テストは同様に便利で効率的ではありません。私はWebソフトウェアを開発していますが、UI全体をテストするプログラムがあるかどうかを教えてください...現在Excelマクロをプログラミングしていますが、実際にVBAでテストモジュールを開発する必要がありますか?
  • テストソフトウェアの作成と保守は、短期的には重要な作業です(長期的には効果があります)。関連するテストを書くことは、取得する専門知識でもあります
  • チームで作業し、単独で作業する場合、テスト要件は同じではありません。チームでは、作成していないコードを検証、理解、伝達する必要があるためです。

テストは良いと思いますが、必ず早い段階でテストし、どこに利益があるかをテストしてください。

3
Arthur Havlicek

考慮すべきいくつかの側面。他の回答では言及されていません。

  • 追加のメリット/追加コストは、単体テストの作成経験に依存します
    • 私の最初の単体テストプロジェクトでは、多くのことを学ぶ必要があり、多くの間違いを犯したため、追加費用が3倍になりました。
    • tddでの10年の経験の後、テストを事前に書くために25%長いコーディング時間が必要です。
  • より多くのtdd-modulsを使用しても、手動のGUIテストと統合テストの必要性が依然としてあります。
  • tddは最初から実行した場合にのみ機能します。
    • 既存の成長したプロジェクトにtddを適用することは、費用がかかる/困難です。ただし、代わりに回帰テストを実装できます。
  • 自動テスト(単体テストおよびその他の種類のテスト)を実行するには、maintanace constが必要です。
    • コピー&ペーストでテストを作成すると、testcode-maintanaceが高価になる可能性があります。
    • 経験が増えるにつれ、テストコードはモジュール化され、保守がより簡単になります。
  • 経験が増えると、自動テストを作成する価値がある場合とそうでない場合の感覚がわかります。
    • 例単純なゲッター/セッター/ラッパーを単体テストしても大きなメリットはありません
    • gUIを介して自動テストを記述しない
    • ビジネス層をテストできるように注意します

概要

Tddで開始する場合、特に「時間に制約のある作業環境」にある限り、「高価で無駄なものを取り除く」ように指示する「賢いマネージャー」がいる限り、「コストよりも利益が多い」状態に到達することは困難です。テストのもの」

注:「単体テスト」では、「モジュールを個別にテストする」ことを意味します。

注:「回帰テスト」とは

  • 出力テキストを生成するコードを記述します。
  • 生成の結果がまだ同じであることを確認する「回帰テスト」コードを記述します。
  • 回帰テストは、結果が変化するたびに通知します(これは問題ないか、新しいバグの指標になる場合があります)。
  • 「回帰テスト」の考え方は approvaltests に似ています。
    • ...結果のスナップショットを撮り、それらが変更されていないことを確認します。
3
k3b

プログラマは、ほとんどのタスクを扱う人々のように、実際に完了するまでにかかる時間を過小評価しています。そのことを念頭に置いて、テストを書くのに10分を費やして、実際には大量のコードを書くのに費やしたであろう時間が、テスト中に行ったのと同じ関数名とパラメーターを考え出すのに費やしたと見なすことができます。 。これはTDDシナリオです。

テストを書くのではなく、クレジットカードを持っているのとよく似ています。より多くの費用をかけるか、より多くのコードを書く傾向があります。コードが増えるほどバグが増えます。

コード全体をカバーするか、まったくカバーしないかを決定する代わりに、アプリケーションの重要で複雑な部分に焦点を当ててテストすることをお勧めします。銀行のアプリでは、それは利息の計算かもしれません。エンジン診断ツールには、複雑な校正プロトコルが含まれている場合があります。あなたがプロジェクトに取り組んできたなら、おそらくそれが何で、どこにバグがあるのか​​知っているでしょう。

ゆっくり始めます。判断する前にある程度の流暢さを築いてください。いつでも止められます。

3
JeffO

私はあなたの経験に関係があります-私たちのコードベースはほとんどテストがなく、ほとんどテスト不可能でした。何かを開発するには文字通り時代を要し、プロダクションのバグを修正するには新しい機能から貴重な時間がかかりました。

部分的な書き直しのために、すべてのコア機能のテストを書くことを誓った。最初はかなり時間がかかり、私の生産性は著しく低下しましたが、その後私の生産性はこれまでになく向上しました。

その改善の一部は、私が生産のバグを減らし、その結果、中断が減ったことでした->いつでもより集中できました。

さらに、コードを個別にテストしてデバッグする能力は、実際に大きな利益をもたらします。一連のテストは、手動でのセットアップ以外ではデバッグできないシステムよりもはるかに優れています。 g。アプリを起動し、画面に移動して何かをします...おそらく数十回

ただし、最初は生産性が低下していることに注意してください。時間のプレッシャーがまだ狂っていないプロジェクトでのテストについて学び始めます。また、グリーンフィールドプロジェクトで開始してみてください。レガシーコードの単体テストは非常に難しく、優れたテストスイートがどのように見えるかを知っているときに役立ちます。

1
Christian Sauer

TDDの見過ごされがちな利点は、変更を加えるときにテストが新しいバグを導入していないことを確認するための保護手段として機能することです。

TDDのアプローチは間違いなく最初は時間がかかりますが、重要なのはコードが少ないと書くことです。これは、問題が少なくなることを意味します。当然のことながら、あなたがしばしば含めるこれらのすべての口笛は、コードベースにはなりません。

映画Swordfishには、記憶が機能する場合、ハッカーが銃を頭に向けて作業しなければならない場面があり、それ以外の場合は気が散ります。重要なのは、ヘッドスペースがコードにあり、顧客があなたに向かって叫んだり、他の優先事項を圧迫したりして、何ヶ月も待つよりも、自分の側に時間があるときの方がはるかに簡単です。

開発者は、後でバグを修正する方がコストがかかることを理解していますが、それを頭に入れてください。現在のコード方法をコーディングするために1日あたり500ドル、またはTDDの方法で書いた場合は1000ドルを支払うことができる場合、2番目のオファーを作成する人から手を離されます。テストを雑用と見なすのをやめ、それをお金の節約と見なすのが早ければ早いほど、よりよい結果が得られます。

1
Robbie Dee

以前の答えを補足するために:テスト自体が目的ではないことを覚えておいてください。テストを行う目的は、アプリケーションが進化を通じて、予期しないコンテキスト内などで期待どおりに動作するようにすることです。

したがって、テストを記述することは、エンティティのすべてのエンドポイントのすべての動作を証明することを意味しません。これは一般的なエラーです。多くの開発者は、すべての関数、オブジェクト、メソッド、プロパティなどをテストする必要があると考えています。これにより、ワークロードが高くなり、無関係なコードやテストが大量に発生します。このアプローチは、大部分の開発者が全体的な振る舞いを認識せず、相互作用の領域のみを確認できる大規模なプロジェクトで一般的です。

疎リソースとテストを処理するときの正しいアプローチはかなり明白で常識的ですが、一般的には正式化されていません:まず、テストリソースを高レベルの機能に投資します。そして、徐々に特異性に下降します。これは、ある時点で、孤独な開発者として、単体テストだけでなく、機能/統合などにも焦点を当てることになります。テストし、時間のリソースに応じて、計画および検討するように、メインの単一機能に徐々に移行します。 高レベルのテストは、低レベル/単体テストに対処し、手持ちのリソースに応じてテスト開発戦略を計画するために必要な情報を提供します。

たとえば、ブラックボックスとして最初に処理チェーンをテストするとします。極端な状態を考慮していない動作が原因でチェーンの一部のメンバーに障害が発生した場合は、このメンバーだけでなく他のメンバーでも機能を保証するテストを作成します。その後、お届けします。次のサイクルでは、ネットワークに障害が発生することがあります。したがって、脆弱である可能性のあるモジュールでこのような問題に対処するテストを記述します。等々。

0
RodolfoAP