TDDの経験とコードのテスト方法に関する考察

最近、エンジニアリングエンジニアリングレクチャーが当社で開催され、これがTDDの概要であることがわかりました。

ああ、そうじゃない! 「時々戻ってくる」(c)スティーブン・キング



前の作業では、この手法の実装に3年を費やしました。 痛かった。 経営陣は、TDDが会社の問題を解決すると信じていました。 現実はこれと著しく矛盾していました。 このすべてが、ソビエト時代のすり減った記憶を呼び起こしました。 私は「共産主義の勝利への前進」のポスターを壁にぶら下げ、「マルクスの教義は全能である」という言葉を思い出した。





TDD コンサバトリーの何が問題になっていますか?



免責事項



残念ながら、私の投稿は、テストに反対しているという意味で多くの人に理解されていました。 特に、すべての症状の単体テストに対して。 これは完全に真実ではなく、むしろ、まったく真実ではありません。



ここで重要な発言をコピーします。これは投稿の最後にあり、あまり印象的ではありませんでした。

単体テストが非常に適切であり、それらの使用が正当化される場合、3種類のコードがあります。

  1. 信頼性の高いソフトウェア-たとえば、飛行機、発電所などのソフトウェア
  2. 簡単に分離されたコード-アルゴリズムなど
  3. ユーティリティ-システムで非常に広く使用されるコードなので、事前に徹底的に磨く価値があります


ユニットテストを書くのが簡単で簡単な場合、つまりコードを簡単に分離できる場合は、痛み、汗、血で傷つけられている私の経験を詳しく読む必要はありません。 そうでない場合は、次のケースが排他的な単一のケースであることに注意してください。



まず、用語を定義しましょう。



用語



手動テスト

機能は、標準のUIを使用して、「ライブ」システムで手動でテストされます。

これは、QAの一般的な従来のテスト方法です。



機能テスト

プログラマーは、ある種の「テスト」UIを作成します。これにより、これらのモジュールの相互作用により、「ライブ」システムで特定のスクリプトを実行できます。

これは、プログラマが使用する非常に一般的なテスト方法です。



単体テスト

プログラマーは、他のモジュールなしで「隔離された」環境で実行できるテストを作成します。 動作中にテストされたコードが適用される他のモジュールは、モックに置き換えられます。 したがって、コンパイル後にビルドマシンでテストを自動的に実行できます。

このようなテストを使用する傾向があります。 また、プログラマーは、使用に切り替えるために(道徳的および管理的)圧力を受けています。



TDDに関する個別の注意

TDDは、単体テストを広範囲に使用するプログラミング手法です。 また、ユニットテストに問題がある場合は、TDDが問題を追加する可能性がありますが(これは成功します)、決して軽減することはできません。



「コードのエラー」

コードはエラー付きで記述されており、プログラマの意図とは異なる動作をします。



「統合エラー」

2人のプログラマーが相互作用するモジュール/クラスを作成し、プロトコルを誤解しました。 プロトコルは、関数に渡されるパラメーターと、正しい/有効な呼び出しシーケンスの両方を参照します。

さらに、各クラスは「きれいに」書くことができますが、まとめるとシステムの正しい動作を提供します。



「マルチスレッディングおよびタイミングエラー」

複数のスレッドが作業に参加している場合、共有リソースまたは呼び出しシーケンスへのアクセスに関連するエラーが発生する可能性があります。 これらは、私が遭遇した最もとらえどころのない(メモリ破損後)バグです。



UIエラーと予期しないエラー

UIは要件をまったく満たしていないか、何らかの形で特定の特定の状況を誤って処理します。

間違ったデータの入力を許可するか、否定的な結果の場合に十分に明確なメッセージを表示しないとしましょう。



さまざまな種類のテストの長所と短所



マニュアル 機能的 単位
「コードのエラー」を見つける機能 はい はい はい
「統合エラー」を見つける機能 はい はい いや
「マルチスレッディングおよびタイミングエラー」を見つける機能 部分的に 部分的に いや
「UIエラー」および「コンティンジェンシーエラー」を見つける機能 はい 部分的に いや
さまざまな入力でテストする機能 低い 許容できる とても高い
テストを自動化する機能 とても低い 低い はい
追加のプログラミング作業 いや いいえ... x1.5 x2 ... x5




私の経験によると(残念ながら正確な統計情報はありません)、「コードのエラー」は、かなり複雑なシステムのすべてのバグの30%未満を占めています。 プログラマが十分な経験を積んでいれば、そのようなエラーの数はさらに少なくなります。

このようなエラーの大部分は、「コードレビュー」(コードレビュー)および機能テストを使用して完全に検出されます。



単体テストでは、考えられるすべての入力データに至るまで、さまざまなオプションを使用してコードをテストできます。 コードを非常に慎重にテストできます。「最後のコンマまで」できます。

問題は、実際のシステムで発生する可能性がある特定の状況があることです。 このセットを超えたテストは無関係であり、時間の無駄です。

機能テストは通常​​、考えられる状況の完全に「合理的な」セットをカバーします。



単体テストの最大の強みは自動化です。

しかし、ここで私は個人的に(3年以上の仕事で)単体テストがバグを書いてからかなり長い時間を経てバグを見つけるのに役立つ状況に出くわしませんでした。

つまり、単体テストは、書いてから非常に短時間で効果的です(バグを見つけるのに役立ちます)。

何かをキャッチするために、ビルダーでユニットテストが自動的に実行されるのを見たことはありません。 彼らはそこで「きれいなものをきれいにする」。 そして、もちろん、リーダーシップの安らぎに仕えます。 :)



単体テストのマイナスは、mokの作成とプログラミングに費やさなければならない多大な努力です。 そのため、単体テストを使用した開発に必要な時間は、単体テストを使用しない場合よりも2〜5倍長くなります。



もちろん、コードが他のモジュールをほとんど使用しないため、完全に分離するのが非常に簡単な場合、単体テストは機能テストと実質的に重複し、それらの違いは名前と技術的な詳細のみです。



要約:

単体テストでは、システムの信頼性が大幅に向上することはありません。

単体テストが非常に適切であり、それらの使用が正当化される場合、3種類のコードがあります。

  1. 信頼性の高いソフトウェア-ここでは無料
  2. 簡単に分離されたコード-単体テストの作成は簡単でシンプルで、コストは機能テストに過ぎません
  3. ユーティリティ-システムで非常に広く使用されるコードなので、事前に徹底的に磨く価値があります
他のすべてのケースでは、ユニットテストのユニットコスト/ベネフィット比はかなり低いです。 単体テスト(特に、コード検査)を使用して検出されたバグを処理するためのはるかに安価な方法があります。

エラーのコストが非常に高い場合(たとえば、飛行機や発電所用のソフトウェアを作成する場合)、コストはあまりかかりません。ユニットテストを使用する必要があります。 しかし、通常、エラーのコストははるかに少なくなります。



組織的および心理的瞬間



バックフィルの質問:プログラマーがユニットテストを十分に作成したことを誰がどのように確認できますか?



単体テストをチェックするための2つの可能なオプションがあります。

インストゥルメンタルチェック

コードのすべての行がテストの一部として実行されたかどうかをテストでコードの「カバレッジ」を測定することが可能です。 私はそのようなチェックが使用されるのを見たことがありません。 もちろん、そのようなテストは、テストがコードを「カバー」することを検証できますが、テストが可能な入力を「カバー」することは検証できません。



別のプログラマーまたはスーパーバイザーによる単体テスト検査

これがどのように行われるかを見ました。 単体テストの作成は非常に退屈な作業です。 それらを理解することは一般に暗闇です。 つまり、あなたはそれを理解することができますが、それは深刻な量の時間とモチベーションを必要とします。 実装の最初の段階で、人々は、ユニットテストとTDDが何であるかを理解するためにすべてを正しく行うことに興味と動機を持っていました。 しかし、すぐに合格しました。



したがって、プログラマーを制御してユニットテストをうまく書くことはかなり困難です。

制御と管理のプレッシャーが減少するとすぐに、プログラマー、怠け者は、「テスト用」の単体テストをますます作成し、手動または機能テストを使用してコードをテストする傾向があります。

エラーコストがそれほど大きくないシステムの場合、プログラマーは単体テストの公正な使用に偏執するほどのプレッシャーを感じません。



プログラマーがコード内の何かを見逃した場合、QAで、または既にクライアントでキャッチし、修正のためにバグが返されます。 フィードバックにより、コードを真剣かつ慎重に受け止めます。

プログラマがテストの作成で何かを見逃しても、誰もそれに気付かないでしょう。 フィードバックがないため、問題に不注意に関係することができます。

プログラマが開発に5倍の時間を費やしたとしても、テスト、moki、tests、mokiなどを細心の注意を払ってカットするのではなく、Habrahabr 読み続けます。



他にどのように単体テストを「機能させる」ことができますか? テストが別のプログラマーによって書かれた場合に機能するはずであり、何よりもコード自体までです。

そして、TDDに行きます。



テスト駆動開発



テストが以前に記述され、プログラマーに入力として提供される場合、それは「技術的要件」になります。 もちろん、テストを作成する人は、必要なすべてのmokeyを事前に作成してプログラムする必要があります。 ハハ、私は他の人のためにテストをプログラムすることが仕事であるプログラマにはなりたくないでしょう。



さて、プログラマー自身が事前に自分のコードのテストを作成できますか?

私の経験では、いやいや。 プログラマー(および私と私がこれについて話し合った大多数)は、反対の方向に考えています。



はい、最初は人々は方法論に正直に従うことを試みました。 しかし、しばらくして、彼らは最初にコードを書き始め、それからテストを追加しました。 そしてしばらくして、テストの汎用性と綿密さが失われました。 そして、彼らが尋ねるので、「shtob was」がまったく書かれました。



しかし、それも必要ですか?



All Articles