特定の言語で単体テストを行う方法について多くの質問がありましたが、「何を」、「なぜ」、「いつ」を質問する質問はありませんでした。
- それは何ですか?
- それは私にとって何をしますか?
- なぜ使用する必要があるのですか?
- いつ使用する必要がありますか (使用しない場合も)?
- よくある落とし穴と誤解とは
特定の言語で単体テストを行う方法について多くの質問がありましたが、「何を」、「なぜ」、「いつ」を質問する質問はありませんでした。
単体テストとは、大まかに言えば、テスト コードを使用してコードの一部を分離してテストすることです。すぐに思いつく利点は次のとおりです。
テスト コードがファイルへの書き込み、データベース接続のオープン、またはネットワーク経由での処理を行う場合は、統合テストとしてより適切に分類されることに注意してください。統合テストは良いことですが、単体テストと混同しないでください。単体テスト コードは、短く、簡潔で、すばやく実行できる必要があります。
単体テストのもう 1 つの見方は、最初にテストを作成することです。これは、テスト駆動開発 (略して TDD) として知られています。TDD には次の利点があります。
単体テストをまだ行っていない場合は、開始することをお勧めします。良い本を入手してください。概念はそれらの間で非常に移植可能であるため、実際にはどの xUnit-book でも構いません。
単体テストを書くのが面倒な場合があります。そのようになったら、助けてくれる人を見つけて、「いまいましいコードを書くだけ」という誘惑に抵抗してください。単体テストは皿洗いによく似ています。いつも楽しいとは限りませんが、比喩的なキッチンをきれいに保ち、本当にきれいにしたいと思っています. :)
編集:それがそれほど一般的かどうかはわかりませんが、1つの誤解が頭に浮かびます. プロジェクト マネージャーが、単体テストのためにチームがすべてのコードを 2 回書く必要があると言っているのを聞いたことがあります。そのように見えたり感じたりする場合は、間違っています。通常、テストを作成すると開発がスピードアップするだけでなく、他の方法では得られない便利な「これで完了です」という指標も得られます。
私はダンに同意しません (ただし、答えないほうがよいかもしれませんが)...しかし...
単体テストは、システムの動作と機能をテストするコードを記述するプロセスです。
テストによってコードの品質が向上することは明らかですが、それは単体テストの表面的な利点にすぎません。実際の利点は次のとおりです。
保守可能で高品質の製品をクライアントに提供することがあなたの利益になるため、単体テストを行う必要があります。
実世界の動作をモデル化するシステムまたはシステムの一部に使用することをお勧めします。つまり、エンタープライズ開発に特に適しています。使い捨て/ユーティリティプログラムには使用しません。テストに問題のあるシステムの部分には使用しません (UI は一般的な例ですが、常にそうとは限りません)。
最大の落とし穴は、開発者が大きすぎるユニットをテストしたり、メソッドをユニットと見なしたりすることです。これは、制御の反転を理解していない場合に特に当てはまります。その場合、単体テストは常にエンドツーエンドの統合テストになります。単体テストは個々の動作をテストする必要があり、ほとんどのメソッドには多くの動作があります。
最大の誤解は、プログラマーはテストすべきではないということです。悪い、または怠惰なプログラマーだけがそれを信じています。あなたの屋根を作っている人はそれをテストすべきではありませんか? 心臓弁を交換する医師は、新しい弁を検査すべきではありませんか? コードが意図したとおりに動作することをテストできるのはプログラマーだけです (QA はエッジ ケースをテストできます - プログラマーが意図していないことを実行するように指示されたときにコードがどのように動作するか、およびクライアントは受け入れテストを実行できます - コードは動作しますか?クライアントが何をするために支払ったか)
「新しいプロジェクトを開いてこの特定のコードをテストする」のとは対照的に、単体テストの主な違いは、自動化されているため、繰り返し可能であるということです。
コードを手動でテストすると、コードが現在の状態で完全に機能していると確信できる場合があります。しかし、1週間後、少し変更を加えたときはどうでしょうか。コードに何か変更があった場合は、手動で再テストしてもよろしいですか?おそらくそうではありません:-(
ただし、テストをいつでも1回クリックするだけで、まったく同じ方法で数秒以内に実行できる場合は、何かが壊れたときにすぐに表示されます。また、単体テストを自動ビルドプロセスに統合すると、一見完全に無関係な変更によってコードベースの離れた部分で何かが壊れた場合でも、バグが警告されます。その特定の機能を再テストする必要があります。
これは、手動テストに対する単体テストの主な利点です。しかし、待ってください、もっとあります:
単体テストフレームワークを使用すると、テストの作成と実行が簡単になります。
私は大学でユニットテストを教えられたことはなく、それを「取得」するのにしばらく時間がかかりました。私はそれについて読んで、「ああ、そうだ、自動化されたテスト、それは私が推測するクールかもしれない」と行った、そしてそれから私はそれを忘れた。
私が実際に要点を理解するまでにはかなり長い時間がかかりました。たとえば、大規模なシステムで作業していて、小さなモジュールを作成しているとします。それはコンパイルされ、あなたはそれをそのペースに通し、それはうまく機能し、あなたは次のタスクに移ります。9か月後、2つのバージョンの後で、他の誰かがプログラムの一見無関係な部分に変更を加え、モジュールが壊れます。さらに悪いことに、彼らは変更をテストし、コードは機能しますが、モジュールはテストしません。地獄、彼らはあなたのモジュールが存在することさえ知らないかもしれません。
そして今、あなたは問題を抱えています:壊れたコードはトランクにあり、誰も知りません。最良のケースは、出荷前に内部テスターがそれを見つけることですが、ゲームの後半にあるコードを修正するにはコストがかかります。そして、内部テスターがそれを見つけられない場合...まあ、それは確かに非常に高価になる可能性があります。
解決策は単体テストです。コードを書くときに問題が発生しますが(これは問題ありません)、手動で行うこともできます。本当の見返りは、完全に異なるプロジェクトに取り組んでいるときに、9か月後に問題が発生することですが、夏のインターンは、これらのパラメーターがアルファベット順になっていると、よりきれいに見えると考えています。その後、単体テストあなたが書いた帰り道は失敗し、誰かがパラメータの順序を元に戻すまでインターンに物を投げます。それがユニットテストの「理由」です。:-)
単体テストと TDD の哲学的な長所に少し触れて、TDD 啓蒙への道のりの暫定的な最初のステップで私を驚かせたいくつかの重要な「電球」観察を示します (オリジナルまたは必ずしもニュースではありません)...
TDD は、2 倍の量のコードを記述することを意味するものではありません。通常、テスト コードはかなり短時間で簡単に作成でき、設計プロセスの重要な部分であり、非常に重要です。
TDD は、いつコーディングをやめるべきかを理解するのに役立ちます! テストによって、今のところ十分にやったという確信が得られ、微調整をやめて次の作業に進むことができます。
テストとコードが連携して、より良いコードを実現します。あなたのコードは悪い/バグがある可能性があります。あなたのテストは悪い/バグがある可能性があります。TDDでは、両方が悪い/バグがかなり少ない可能性に頼っています。多くの場合、修正が必要なテストですが、それでも良い結果です。
TDD は便秘のコーディングに役立ちます。やるべきことが多すぎて、どこから始めればいいのかわからないという気持ちを知っていますか?金曜日の午後です。さらに数時間先延ばしすると... TDD を使用すると、必要だと思われることを非常に迅速に具体化し、コーディングをすばやく進めることができます。また、実験用ネズミのように、私たちは皆、その大きな青信号に反応し、再びそれを見るために一生懸命努力していると思います!
同様に、これらのデザイナー タイプは、自分が取り組んでいるものを見ることができます。彼らは、ジュース/タバコ/iPhone休憩のためにさまよって、どこに着いたかについての視覚的な手がかりをすぐに与えるモニターに戻ることができます. TDD も同様の機能を提供します。生命が介入すると、どこにたどり着いたかが簡単にわかります...
Fowler は次のように言ったと思います。これは、残りのコード カバレッジがひどく不完全であっても、最も役立つと思われるテストを作成する許可を与えてくれるものだと解釈しています。
TDD は、あらゆる種類の驚くべき方法で役立ちます。優れた単体テストは、何をすべきかを文書化するのに役立ち、あるプロジェクトから別のプロジェクトにコードを移行するのに役立ち、テストを行っていない同僚よりも不当な優越感を与えることができます:)
このプレゼンテーションは、おいしい良さのテストに伴うすべての優れた紹介です.
Gerard Meszaros による xUnit Testing Patterns の本をお勧めします。サイズは大きいですが、単体テストの優れたリソースです。単体テストの基本について説明している彼の Web サイトへのリンクを次に示します。 http://xunitpatterns.com/XUnitBasics.html
時間を節約するために単体テストを使用します。
ビジネス ロジック (またはデータ アクセス) を構築する場合、機能のテストには、多くの場合、まだ完了しているかどうかにかかわらず、多くの画面に何かを入力する必要があります。これらのテストを自動化すると、時間を節約できます。
私にとって、単体テストは一種のモジュール化されたテスト ハーネスです。通常、パブリック関数ごとに少なくとも 1 つのテストがあります。さまざまな動作をカバーする追加のテストを作成します。
コードを開発するときに考えた特殊なケースはすべて、単体テストのコードに記録できます。単体テストは、コードの使用方法の例のソースにもなります。
新しいコードが単体テストで何かを壊していることを発見してから、コードをチェックインし、フロントエンド開発者に問題を見つけてもらう方がはるかに高速です。
データ アクセスのテストでは、何も変更しないか、後からクリーンアップするテストを作成するようにしています。
単体テストは、すべてのテスト要件を解決できるわけではありません。彼らは開発時間を節約し、アプリケーションのコア部分をテストできます。
Kent Beckによって普及しているTDDアプローチを使用してプロジェクトを開発する場合は、 NUnit、xUnit、JUnitなどのライブラリが必須です。
テスト駆動開発(TDD)の概要またはケントベックの著書「テスト駆動開発:例による」を読むことができます。
次に、テストがコードの「適切な」部分をカバーしていることを確認したい場合は、 NCover、JCover、PartCoverなどのソフトウェアを使用できます。彼らはあなたのコードのカバー率を教えてくれます。TDDにどれだけ熟練しているかによって、十分に練習したかどうかがわかります:)
これが私の見解です。単体テストとは、実際のソフトウェアが意図したとおりに機能することを検証するためのソフトウェア テストを作成することです。これは Java の世界ではjUnitから始まり、PHP やSimpleTestおよびphpUnitのベスト プラクティスになりました。これは、エクストリーム プログラミングの核となる実践であり、編集後もソフトウェアが意図したとおりに機能することを確認するのに役立ちます。十分なテスト カバレッジがあれば、主要なリファクタリング、バグ修正、または機能の追加を迅速に行うことができ、他の問題が発生する心配ははるかに少なくなります。
すべての単体テストを自動的に実行できる場合に最も効果的です。
単体テストは、通常、オブジェクト指向の開発に関連付けられています。基本的な考え方は、コードの環境をセットアップして実行するスクリプトを作成することです。アサーションを記述し、受け取るべき意図した出力を指定してから、上記のようなフレームワークを使用してテスト スクリプトを実行します。
フレームワークはコードに対してすべてのテストを実行し、各テストの成功または失敗を報告します。phpUnit はデフォルトで Linux コマンド ラインから実行されますが、HTTP インターフェースも利用できます。SimpleTest は本質的に Web ベースであり、起動と実行がはるかに簡単です (IMO. xDebug と組み合わせることで、phpUnit はコード カバレッジの自動統計を提供することができます。
一部のチームは、変更をコミットするたびに単体テストが自動的に実行されるように、subversion リポジトリからフックを作成します。
単体テストをアプリケーションと同じリポジトリに保持することをお勧めします。
単体テストとは、アプリケーションコードをテストするコードを作成することです。
名前のUnitの部分は、一度に小さな単位のコード(たとえば、1つのメソッド)をテストすることを目的としています。
xUnitは、このテストを支援するためにあります。xUnitは、これを支援するフレームワークです。その一部は、どのテストが失敗し、どのテストが合格したかを通知する自動テストランナーです。
また、各テストで必要な共通コードを事前にセットアップし、すべてのテストが終了したら破棄する機能もあります。
try catchブロック全体を自分で作成しなくても、予期された例外がスローされたことを確認するためのテストを行うことができます。
あなたが理解していない点は、NUnit(など)のようなユニットテストフレームワークが中小規模のテストの自動化に役立つということだと思います。通常、GUIでテストを実行できます(たとえば、NUnitの場合)。ボタンをクリックするだけで、できれば進行状況バーが緑色のままになります。赤に変わった場合、フレームワークはどのテストが失敗し、何が正確に失敗したかを示します。通常の単体テストでは、アサーションを使用することがよくあります。たとえばAssert.AreEqual(expectedValue, actualValue, "some description")
、2つの値が等しくない場合、「説明:<expectedValue>が必要ですが、<actualValue>でした」というエラーが表示されます。
したがって、結論として、単体テストは、開発者にとってテストをより速く、より快適にするでしょう。同じプロジェクトの他の開発者のビルドプロセスを中断しないように、新しいコードをコミットする前にすべての単体テストを実行できます。
単体テストとは、コードの単位が依存するインフラストラクチャを必要とせずに、コードの単位 (単一の関数など) をテストすることです。つまり、単独でテストします。
たとえば、テストしている関数がデータベースに接続して更新を行う場合、単体テストではその更新を行いたくない場合があります。統合テストであればそうするでしょうが、この場合はそうではありません。
したがって、単体テストは、データベース更新の副作用なしで、テストしている「関数」に含まれる機能を実行します。
関数がデータベースからいくつかの数値を取得し、標準偏差の計算を実行したとします。ここで何をテストしようとしていますか? 標準偏差が正しく計算されているか、またはデータがデータベースから返されているか?
単体テストでは、標準偏差が正しく計算されていることをテストしたいだけです。統合テストでは、標準偏差の計算とデータベースの取得をテストします。
Use Testivus. All you need to know is right there :)
まず第一に、ユニットテストまたは他の種類の自動テスト(統合、ロード、UIテストなど)について話すかどうかにかかわらず、あなたが提案するものとの主な違いは、自動化され、再現可能であり、人的資源を必要としないことです消費されます(=誰もテストを実行する必要はありません。通常、ボタンを押すだけで実行されます)。
テスト駆動開発は、単体テストという用語を引き継いでいます。古いタイマーとして、より一般的な定義について言及します。
単体テストは、大規模なシステムで単一のコンポーネントをテストすることも意味します。この単一のコンポーネントは、dll、exe、クラス ライブラリなどである可能性があります。マルチシステム アプリケーション内の単一のシステムである可能性もあります。したがって、最終的に単体テストは、より大きなシステムの単一部分と呼びたいもののテストになります。
次に、すべてのコンポーネントがどのように連携するかをテストすることにより、統合テストまたはシステム テストに進みます。
私は FoxForward 2007 でのユニット テストに関するプレゼンテーションに参加しましたが、データを操作するものはユニット テストしないように言われました。結局のところ、ライブ データでテストすると、結果は予測できなくなります。また、ライブ データでテストしないと、作成したコードを実際にテストすることにはなりません。残念ながら、それは私が最近行っているコーディングのほとんどです。:-)
最近、設定を保存および復元するルーチンを書いていたときに、TDD を試してみました。まず、ストレージ オブジェクトを作成できることを確認しました。次に、呼び出す必要のあるメソッドが含まれていること。それから、私はそれを呼び出すことができました。次に、パラメーターを渡すことができます。次に、特定のパラメーターを渡すことができます。いくつかの異なる構文について、指定した設定を保存し、変更してから復元できることを最終的に確認するまで、などを繰り返しました。
最後までやり遂げることはできませんでした。なぜなら、ルーティンが必要だったからです。でも、いい練習になりました。
がらくたの山を与えられ、新しい機能やコードを追加すると現在のセットが壊れる可能性があることを知っているクリーンアップの永続的な状態に陥っているように見える場合はどうしますか?現在のソフトウェアは家のようなものです。カード?
では、単体テストを行うにはどうすればよいでしょうか。
あなたは小さく始めます。私が参加したばかりのプロジェクトには、数か月前まで単体テストがありませんでした。カバレッジがそれほど低いときは、カバレッジのないファイルを選択して「テストを追加」をクリックするだけでした。
現在、達成率は 40% を超えており、簡単に達成できる成果のほとんどを取り除くことができました。
(最も良い点は、この低いレベルのカバレッジでも、間違ったことをしているコードの多くのインスタンスに既に遭遇しており、テストがそれをキャッチしたことです。これは、人々にさらにテストを追加するように促す大きな動機です。)
これは、単体テストを行う必要がある理由の答えです。
以下の 3 つのビデオでは、JavaScript での単体テストについて説明していますが、一般的な原則はほとんどの言語に適用されます。
単体テスト: 今数分で数時間節約 - Eric Mann - https://www.youtube.com/watch?v=_UmmaPe8Bzc
JS 単体テスト (とても良い) - https://www.youtube.com/watch?v=-IYqgx8JxlU
テスト可能な JavaScript の記述 - https://www.youtube.com/watch?v=OzjogCFO4Zo
今、私はこの主題について学んでいるので、100% 正しいとは限らず、ここで説明していることよりも多くのことがありますが、単体テストに関する私の基本的な理解は、いくつかのテスト コードを記述することです (これは、テスト コードとは別に保持されます)。これは、関数が必要とする入力 (引数) を使用してメイン コード内の関数を呼び出し、コードが有効な戻り値を取得するかどうかをチェックします。有効な値が返された場合、テストの実行に使用している単体テスト フレームワークは緑色のライト (すべて正常) を示します。値が無効な場合は赤色のライトが表示され、問題を修正する前にすぐに問題を修正できます。新しいコードを本番環境にリリースします。テストを行わないと、実際にはエラーをキャッチできなかった可能性があります。
したがって、現在のコードのテストを作成し、テストに合格するようにコードを作成します。数か月後、あなたまたは他の誰かがメイン コードの関数を変更する必要があります。以前にその関数のテスト コードを既に記述していたため、再度実行すると、コーダーが関数に論理エラーを導入したか、何かを完全に返すためにテストが失敗する可能性があります。その関数が返すはずのものとは異なります。繰り返しになりますが、テストが実施されていないと、エラーを追跡するのが難しくなる可能性があります。これは、他のコードにも影響を与える可能性があり、見過ごされる可能性があるためです。
また、ブラウザでページごとに手動で行うのではなく、コードを実行してテストするコンピューター プログラムがあるため、時間を節約できます (javascript の単体テスト)。Web ページ上の何らかのスクリプトで使用されている関数を変更すると、その関数はすべて正常に機能し、新しい意図された目的に適しているとします。ただし、引数のために、コード内の別の場所に別の関数があり、その関数が正しく動作するために新しく変更された関数に依存しているとしましょう。この従属関数は、最初の関数に変更を加えたために動作を停止する可能性がありますが、コンピューターによって自動的に実行されるテストが実施されていなければ、実際に実行されるまでその関数に問題があることに気付かないでしょう。あなた'
繰り返しになりますが、アプリケーションの開発中にテストを実行すると、コーディング中にこの種の問題を発見できます。テストが実施されていないと、アプリケーション全体を手動で確認する必要があり、それでもバグを見つけるのは難しい場合があります。素朴に本番環境に送信し、しばらくすると親切なユーザーがバグレポートを送信します (これはテスト フレームワークでのエラー メッセージほど良くはありません)。
この件について初めて聞いたとき、自分のコードをまだテストしていないのではないかと思うと、かなり混乱します。そして、あなたが書いたコードは、「なぜ別のフレームワークが必要なのですか?」... はい、すでにコードをテストしていますが、コンピューターの方が優れています。関数/コード単位に対して十分なテストを一度書くだけで、残りは強力なCPUによって処理され、変更を加えたときにすべてのコードがまだ機能していることを手動で確認する必要はありません。あなたのコード。
また、望まない場合はコードの単体テストを行う必要はありませんが、プロジェクト/コード ベースが大きくなり始め、バグが発生する可能性が高くなるため、成果が得られます。