JavaRush /Java Blog /Random-JA /TDD と単体テストとは [翻訳]
Dr-John Zoidberg
レベル 41
Марс

TDD と単体テストとは [翻訳]

Random-JA グループに公開済み
この記事は、書籍『The Complete Software Career Guide』の章を改作したものです。著者の John Sonmez が執筆し、いくつかの章を彼の Web サイトに掲載しています。
TDD と単体テストとは [翻訳] - 1

初心者向けの短い用語集

単体テストまたは単体テストは、プログラムのソース コードの個々のモジュールが正しいかどうかをチェックできるプログラミングのプロセスです。アイデアは、すべての重要な関数またはメソッドのテストを作成することです。 回帰テストは、ソース コードのすでにテストされた領域のエラーを検出することを目的とした、あらゆる種類のソフトウェア テストの一般名です。このようなエラー、つまりプログラムに変更を加えた後、動作し続けるはずのものが動作しなくなる場合は、回帰エラーと呼ばれます。 赤の結果、失敗- テストの失敗。期待される結果と実際の結果との違い。 緑色の結果、合格- 陽性のテスト結果。実際の結果は得られたものと変わりません。***
TDD と単体テストとは [翻訳] - 2
私はテスト駆動開発 (TDD) と単体テストに対して非常に複雑な関係を持っており、好きになったり嫌いになったり、また戻ったりしています。私は熱心なファンであると同時に、これやその他の「ベスト プラクティス」の使用については懐疑的でした。私のこのような態度の理由は、ソフトウェア開発プロセスに深刻な問題が生じているという事実に基づいています。それは、開発者、場合によっては管理者が、「ベスト プラクティス」に属しているという理由だけで、特定のツールや方法論を使用しているということです。それらが使用される本当の理由は依然として不明です。ある日、私はあるプロジェクトに取り組み始めましたが、その過程で、膨大な数の単体テストの対象となるコードを変更することになると知らされました。冗談ではなく、その数は約 3000 でした。これは通常、良い兆候であり、開発者が高度な手法を使用していることを示しています。このアプローチのコードはほとんどの場合構造化されており、よく考えられたアーキテクチャに基づいています。一言で言えば、テストの存在は、プログラマーの指導者としての仕事を容易にするという理由だけであったとしても、私にとっては幸せでした。すでに単体テストがあったので、開発チームをサポートしてもらい、独自のコードを書き始めるだけで済みました。IDE(統合開発環境)を開いてプロジェクトをロードしました。
TDD と単体テストとは [翻訳] - 3
それは大きなプロジェクトでした!「単体テスト」というラベルの付いたフォルダーを見つけました。「素晴らしい」と私は思いました。- 起動して何が起こるか見てみましょう。所要時間はわずか数分で、驚いたことに、すべてのテストが合格し、すべてが緑色になりました ( 「緑色」はテストの肯定的な結果です。コードが期待どおりに動作していることを示します。赤色は「失敗」または失敗を示します)。コードが正しく動作しない場合があります - 翻訳者注)。彼らは全員テストに合格しました。その瞬間、私の中の懐疑心が目覚めました。どうして 3,000 の単体テストが一度に行われ、肯定的な結果が得られたのでしょうか? 私の長年の実践の中で、コード内に単体テストが 1 つも含まれていない状態でプロジェクトに取り組み始めたときのことを思い出せません。何をするか?手動で確認してください!ChY はランダムなテストを 1 つ選択しましたが、これは最も明らかなテストではありませんでしたが、彼が何をチェックしているのかはすぐに明らかでした。しかし、作業中に、何か不条理なことに気づきました。テストには、期待される結果 (アサート) との比較が含まれていませんでした。つまり、実際には何もチェックされていません。テストには特定の手順があり、それらは実行されましたが、テストの最後に実際の結果と期待される結果を比較する必要があるときに、チェックがありませんでした。「テスト」では何もテストされませんでした。別のテストを開きました。さらに良いことに、結果を含む比較演算子がコメントアウトされています。見事に!これはテストに合格するための優れた方法であり、失敗の原因となっているコードをコメントアウトするだけです。別のテストをチェックし、さらに別のテストをチェックしました...どれも何もチェックしませんでした。3,000 回のテストがあり、そのすべてがまったく役に立ちません。単体テストを書くことと、単体テストおよびテスト駆動開発 (TDD) を理解することの間には大きな違いがあります。

単体テストとは何ですか?

TDD と単体テストとは [翻訳] - 4
単体テストの基本的な考え方は、コードの最小の「単位」をテストするテストを作成することです。単体テストは通常​​、アプリケーションのソース コードと同じプログラミング言語で記述されます。これらは、このコードをテストするために直接作成されます。つまり、単体テストは他のコードの正しさをチェックするコードです。単体テストはある意味ではテストではないため、私はこの文脈で「テスト」という言葉をかなり自由に使用しています。彼らは何も経験しません。つまり、単体テストを実行すると、一部のコードが機能しないことが通常は見つからないということです。テストが緑色になるまでコードを変更するため、テストを作成しているときにこれに気づきます。はい、後でコードが変更され、テストが失敗する可能性があります。この意味で、単体テストは回帰テストです。単体テストは、いくつかの手順を実行してソフトウェアが正しく動作するかどうかを確認する通常のテストとは異なります。単体テストを作成するプロセス中に、コードが本来の動作をしているかどうかを発見し、テストが合格するまでコードを変更します。
TDD と単体テストとは [翻訳] - 5
単体テストを作成して、それが成功するかどうかを確認してみてはいかがでしょうか。このように考えると、単体テストは、非常に低いレベルで特定のコード モジュールに対するある種の絶対的な要件になります。単体テストは絶対的な仕様と考えることができます。単体テストでは、これらの条件下で、この特定の入力セットを使用して、このコード単位から取得すべき出力があるかどうかを判断します。真の単体テストでは、一貫したコードの最小単位を特定します。これは、ほとんどのプログラミング言語 (少なくともオブジェクト指向言語) ではクラスです。

単体テストと呼ばれることもあります?

TDD と単体テストとは [翻訳] - 6
単体テストは、統合テストと混同されることがよくあります。一部の「単体テスト」では、複数のクラスをテストするか、大きな単位のコードをテストします。多くの開発者は、実際には低レベルのホワイトボックス テストを作成しているのに、単体テストを作成していると主張しています。この人たちと議論しないでください。実際には統合テストを作成し、本当の単体テストはコードの最小単位を他の部分から分離してテストすることを知っておいてください。単体テストと呼ばれることが多いもう 1 つは、期待値に対するチェックを行わない単体テストです。言い換えれば、実際には何もテストしない単体テストです。ユニット化されているかどうかにかかわらず、テストには何らかの検証が含まれている必要があります。これを、期待される結果に対する実際の結果のチェックと呼びます。この調整によって、テストの合否が決まります。常に合格するテストは役に立ちません。常に失敗するテストは役に立ちません。

単体テストの価値

なぜ私は単体テストの愛好家なのでしょうか? 他のコードから分離された最小のブロックではなく、より大きなコード部分のテストを含む一般化されたテストを「単体テスト」と呼ぶのはなぜ有害なのでしょうか? 一部のテストで、受け取った結果と期待される結果が比較されない場合、何が問題なのでしょうか? 少なくともコードは実行されます。説明してみます。
TDD と単体テストとは [翻訳] - 7
単体テストを実行する主な理由は 2 つあります。 1 つ目は、コード設計を改善することです。 単体テストは実際にはテストではない、と私が言ったことを覚えていますか? 適切な単体テストを作成すると、コードの最小単位を分離する必要があります。これらの試みにより、コード自体の構造の問題が発見されます。テスト クラスを分離し、その依存関係を含めないようにするのは非常に難しいことがわかり、コードが密接に結合しすぎていることに気づく場合があります。テストしようとしているコア機能が複数のモジュールにまたがっていることが判明し、コードの一貫性が十分ではないと思われる場合があります。単体テストを作成するために座っていると、そのコードが何をすべきか全く分かっていないことに突然気づくかもしれません (信じてください、実際にそうなります!)。したがって、単体テストを作成することはできません。そしてもちろん、単体テストでは既成概念にとらわれずに考え、考慮していなかったさまざまな入力セットをテストする必要があるため、コードの実装で本当のバグが見つかる可能性があります。
TDD と単体テストとは [翻訳] - 8
単体テストを作成するときに「コードの最小単位を他のコードから分離してテストする」というルールに厳密に従うと、そのコードやモジュールの設計にあらゆる種類の問題が見つかるはずです。ソフトウェア開発ライフサイクルにおいて、単体テストはテスト活動というよりは評価活動です。 単体テストの 2 番目の主な目的は、ソフトウェア動作の低レベルの仕様として機能できる、自動化された回帰テストのセットを作成することです。それはどういう意味ですか?生地をこねるとき、生地を壊しません。この観点から見ると、単体テストはテスト、より具体的には回帰テストです。ただし、単体テストの目的は、単に回帰テストを作成することではありません。実際には、テストしているコード単位への変更には、ほとんどの場合、単体テスト自体への変更が含まれるため、単体テストでリグレッションが検出されることはほとんどありません。回帰テストは、コードが「ブラック ボックス」としてテストされる高いレベルでより効果的です。このレベルでは、外部の動作は変わらないと予想される一方で、コードの内部構造は変更される可能性があるためです。単体テストは内部構造をチェックし、その構造が変更されても単体テストが失敗しないようにします。それらは使用できなくなり、変更するか、破棄するか、書き直す必要があります。あなたは、多くのベテラン ソフトウェア開発者よりも単体テストの本当の目的についてよく知っています。

テスト駆動開発 (TDD) とは何ですか?

TDD と単体テストとは [翻訳] - 9
ソフトウェア開発プロセスでは、優れた仕様は金に等しいほどの価値があります。TDD のアプローチでは、コードを作成する前に、まず仕様として機能するテストを作成します。つまり、コードが何を実行するかを定義します。これは非常に強力なソフトウェア開発概念ですが、誤用されることがよくあります。通常、テスト駆動開発とは、単体テストを使用してアプリケーション コードの作成をガイドすることを意味します。しかし実際には、このアプローチはどのレベルにも適用できます。ただし、この記事では、アプリケーションに単体テストを使用していることを前提とします。TDD アプローチではすべてが逆転し、最初にコードを書いてからそのコードをテストするための単体テストを作成するのではなく、最初に単体テストを作成してから、そのテストをグリーンにするためのコードを作成します。このように、単体テストはコード開発を「推進」します。このプロセスが何度も繰り返されます。コードが実行すべき機能の詳細を定義する別のテストを作成します。次に、テストが正常に完了するようにコードを作成および変更します。緑色の結果が得られたら、コードのリファクタリングを開始します。つまり、より簡潔にするためにコードをリファクタリングまたはクリーンアップします。このプロセスのチェーンは、最初に単体テストが失敗し (赤)、次にテストに適応するようにコードが作成され、テストが成功することを確認し (緑)、最後にコードが最適化されるため、「赤-緑-リファクタリング」と呼ばれることがよくあります (リファクタリング)。

TDD の目標は何ですか?

TDD と単体テストとは [翻訳] - 10
テスト駆動開発 (TDD) は、単体テストと同様に、誤って使用される可能性があります。自分のやっていることを「TDD」と呼ぶのは非常に簡単で、なぜそのようにしているのか理解せずにそのプラクティスに従うことさえあります。TDD の最大の価値は、品質の仕様を作成するためにテストが実行されることです。 TDDは本質的に、コーディングを記述する前に自動的にチェックできる正確な仕様を記述する実践です。テストは嘘をつかないので最高の仕様です。コードで2週間苦しめられた後でも、彼らは「それは私が言いたかったことではありません」とは言わないでしょう。テストは、正しく記述されていれば、合格するか失敗します。テストは、特定の状況下で何が起こるべきかを明確に示します。したがって、TDD の目標は、実装を開始する前に実装する必要があるものを完全に理解できるようにすることです。TDD を始めたばかりで、テストで何をテストする必要があるのか​​理解できない場合は、さらに質問する必要があります。TDD のもう 1 つの重要な役割は、コードを保存して最適化することです。コードのメンテナンスには費用がかかります。私はよく「最高のプログラマーとは、問題を解決する最短のコードを書く人だ」と冗談を言います。あるいは、エラーの数を減らし、アプリケーションの保守コストを削減する正しい方法を見つけたのはこのプログラマーであるため、この問題を解決する必要がないことを証明し、コードを完全に削除する人さえいます。TDD を使用すると、テストに合格するためのコードのみを作成するため、不必要なコードを作成していないことを完全に確信できます。YAGNI と呼ばれるソフトウェア開発原則があります (それは必要ありません)。TDD は YAGNI を防ぎます。

典型的なテスト駆動開発 (TDD) ワークフロー

TDD と単体テストとは [翻訳] - 11
純粋に学術的な観点から TDD の意味を理解することは困難です。それでは、TDD セッションの例を見てみましょう。机に座って、ユーザーがアプリケーションにログインし、パスワードを忘れた場合に変更できるようにする機能の高レベルの設計を素早くスケッチすることを想像してください。あなたは、ログイン関数の最初の実装から始めて、ログイン プロセスのすべてのロジックを処理するクラスを作成することに決めました。お気に入りのエディターを開き、「空のログインによりユーザーがログインできない」という単体テストを作成します。最初に Login クラスのインスタンス (まだ作成していません) を作成する単体テスト コードを作成します。次に、空のユーザー名とパスワードを渡す Login クラスのメソッドを呼び出すコードを作成します。最後に、期待される結果に対するチェックを記述し、ログインが空のユーザーが実際にログインしていないことを確認します。テストを実行しようとしていますが、Login クラスがないためコンパイルすらできません。この状況を修正し、Login クラスを作成し、そのクラス内にログインするためのメソッドと、ユーザーのステータスをチェックしてログインしているかどうかを確認する別のメソッドを作成します。これまでのところ、このクラスの機能と必要なメソッドは実装されていません。この時点でテストを実行します。これでコンパイルは完了しますが、すぐに失敗します。
TDD と単体テストとは [翻訳] - 12
ここでコードに戻り、テストに合格するための機能を実装します。この場合、これは「ユーザーはログインしていません」という結果が得られることを意味します。再度テストを実行すると、テストは成功しました。次のテストに進みましょう。ここで、「有効なユーザー名とパスワードを入力した場合、ユーザーはログインしている」というテストを作成する必要があると想像してみましょう。Login クラスをインスタンス化し、ユーザー名とパスワードを使用してログインを試みる単体テストを作成します。単体テストでは、ユーザーがログインしているかどうかの質問に対して Login クラスが「はい」と答える必要があるというステートメントを作成します。この新しいテストを実行すると、Login クラスは常にユーザーがログインしていないことを返すため、当然失敗します。Login クラスに戻り、ユーザーがログインしていることを確認するコードを実装します。この場合、このモジュールを分離する方法を理解する必要があります。現時点では、これを行う最も簡単な方法は、テストで使用したユーザー名とパスワードをハードコーディングし、それらが一致する場合は、「ユーザーはログインしています」という結果を返すことです。この変更を加えて両方のテストを実行すると、両方とも成功します。最後のステップに進みましょう。生成されたコードを確認し、コードを再構成して簡素化する方法を探します。したがって、TDD アルゴリズムは次のようになります。
  1. テストを作成しました。
  2. このテスト用にコードを書きました。
  3. コードをリファクタリングしました。

結論

TDD と単体テストとは [翻訳] - 13
現段階で単体テストと TDD について伝えたかったのはこれだけです。実際、コードは非常に複雑でわかりにくい場合があるため、コード モジュールを分離しようとすると多くの困難が伴います。完全に分離して存在するクラスはほとんどありません。代わりに、それらには依存関係があり、それらの依存関係には依存関係が存在する、というようになります。このような状況に対処するために、TDD のベテランはモックを使用します。これは、依存モジュール内のオブジェクトを置き換えることによって個々のクラスを分離するのに役立ちます。この記事は、単体テストと TDD の概要とやや簡略化した紹介にすぎず、ダミー モジュールやその他の TDD テクニックについては詳しく説明しません。その目的は、TDD と単体テストの基本的な概念と原則を理解できるようにすることです。オリジナル - https://simpleprogrammer.com/2017/01/30/tdd-unit-testing/
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION