バグの私の統一理論



この翻訳は、テストに関する一連の記事の続きです。



次に、テスト可能なコードを構築するための実用的なヒントと、実際のプロジェクトに知識を適用する例があります。

PSロシア語翻訳の校正のためのタキシーに感謝します。





バグは3つの基本的なカテゴリに分類できると思います。

  1. 論理的 。 論理的なバグは最も一般的で一般的なものです。 これらは、コード内のifs、ループ、およびその他の同様のロジックです。 (思考:これは正しく機能しません)。
  2. 相互作用のバグ 。 相互作用のバグ-2つの異なるオブジェクトが相互に誤って相互作用する場合。 たとえば、あるオブジェクトの出力は、チェーン内の次のオブジェクトが期待するものではありません。 (思考:宛先へのデータが損なわれた)。
  3. バグを表示します。 表示のバグ-出力(通常は一部のユーザーインターフェイス、UI)が正しく表示されない場合。 重要な点は、この人が何が正しいかを決定することです。 (考え:これは間違って「見える」)




警告:一部の開発者は、ユーザーインターフェイスを構築すると、すべてのバグが表示バグであると考えています! 表示バグとは、テキストがボタンの枠を出るときのエラーなどのエラーを意味します。 しかし、ボタンをクリックして間違ったことが起こった場合は、むしろ相互作用エラー(相互作用のバグ)、またはロジックに何らかの問題(論理的なバグ)が原因です。 ディスプレイのバグは非常にまれです。



プログラム内のバグのタイプの典型的な分布



3種類のバグで最初に気付いたのは、それぞれのバグに遭遇する確率が不均一であることです。 確率に加えて、コードでの検索と修正の複雑さも異なります(これはあなた自身の経験からも覚えているはずです)。 私のWebアプリケーション構築経験では、論理的なバグが最も一般的であり、リンクバグが続き、最後にバグが表示されることが示唆されています。



バグ検出の難しさ



論理的なバグは検出が最も困難です。 理由の1つは、特定の入力条件下でのみ表示され、これらの不思議なセットまたはその複製の検索には、大きな畳み込みが伴うことです。 結合バグは、ほとんどの独立した入力条件下で簡単に再現できるため、検出が容易です。 また、ディスプレイのバグを自分の目で見るだけで、何が間違っているのかをすぐに確認できます。



バグ修正の難しさ



実際の経験から、エラーを修正することがどれほど難しいかがわかります。 ソリューションを見つけるためには、コード実行のすべての方法を理解する必要があるため、論理的なバグを修正することは非常に困難です。 変更を行った後、修正によって既存の機能が損なわれないことも確認する必要があります。 バインドの問題は、例外またはデータの間違った場所で現れるため、修正が簡単です。 ディスプレイのバグ自体は、何が間違っていたかを明確に示しており、すぐに修正方法を知っています。 ユーザーインターフェイスの頻繁な変更を考慮して、最初にプログラムを設計しました。したがって、このような変更を行うのは簡単です。



論理的 バインディング マッピング
発生確率 高い 平均 低い
見つけにくい 難しい かんたん 些細なこと
難易度の修正 高い 平均 低い




テスト容易性は、バグの種類の分布をどのように変更しますか?



テスト可能なコードを書くと、プログラム内のバグの種類の分布に影響することがわかります。 テストの適合性のために、コードは以下を行う必要があります。







これらのルールに従うことで、バインディングのバグが大幅に削減されます。 割合として、論理的なバグの数は増えましたが、すべてのバグの総数は減りました。











テスト自体を1行も書かなくても、テスト可能なコードの恩恵を受けることができるのは興味深いことです。 同様のコードが最高のコードです! (人々がテストの適合性のために「良いコード」を犠牲にするのを聞いたとき、私は彼らがテストテストコードが実際に何であるかを完全に知らないことに気づきます)



単体テストを書くのが大好きです。



単体テストは非常に強力な武器を提供します。 これらのテストは、検出および修正が困難な最も一般的なバグを検出するように設計されています。 単体テストは、バグのバインドを暗黙的に支援するテスト可能なコードの作成にも役立ちます。 その結果、自動化されたテストを作成するときは、主に単体テストに焦点を当てる必要があります。 このような各テストは、1つのクラス/メソッドのロジックのみに焦点を当てています。



単体テストは論理的なバグに焦点を当てています。 彼らはあなたのiとループをチェックしますが、バインディングを直接チェックしません(そしてもちろん彼らはマッピングをチェックしません)



単体テストは、CBT(テスト対象クラス、CUT、テスト対象クラス)に焦点を当てています。 これらのテストが将来のリファクタリングの邪魔にならないようにする必要があるため、これは重要です。 単体テストは、リファクタリングを支援するものであり、妨げるものではありません。 (私は繰り返します:テストがリファクタリングを妨げると誰かが言うのを聞くと、この人はユニットテストが何であるかを理解していないと思います)。



単体テストは、バインディングですべてが正常であると直接言っているわけではありません。 テスト可能なコードを書くように強制することで、暗黙的にこれを行います。



機能テストは接続を確認しますが、それだけではありません。 多くの機能テストがある場合、または機能テストと論理テストが混在している場合、リファクタリングを長時間実行できます。



バグ管理



私はテストをバグの管理と考えるのが好きです(バグを取り除くために)。 すべてのタイプのエラーが同じというわけではないため、集中する必要があるテストを選択します。 私はユニットテストが大好きだとわかりました。 しかし、彼らはよく焦点を合わせなければなりません! テストが1回のパスで多くのクラスをチェックする場合、テスト範囲が良好であることに満足できますが、実際には、その後、「赤」テストに点火した場所を見つけることは困難です。 また、リファクタリングが困難になる場合があります。 私は機能テストで私の生活を楽にします:私にとっては、1つのテストで十分であり、これはバインディングの正確さを証明します。



多くの人がユニットテストを書いていると主張するのを聞きますが、よく調べてみると、機能テスト(バインディングチェック)とユニットテスト(ロジック)が混在していることがわかります。 これは、コードが記述された後にテストが記述されたときに発生し、このため、不適切であることが判明しました。 不適切なコードはモッカーの出現につながります(英語の「モック」-スタブから)-これは多くのスタブを必要とするテストであり、これらのスタブは他のスタブを使用します。 モッカーによるテストを使用すると、ほとんど確信が持てません。 そのようなテストは、メソッドのレベルで何かをアサートするために必要な抽象化のレベルが高すぎます。 これらのテストは実装に深く関係しています(これはスタブ間に多数の接続が存在することで確認できます)。その結果、リファクタリングは非常に苦痛になります。



---------------------------

translated.by/you/my-unified-theory-of-bugs/into-ru/trans

(): My Unified Theory of Bugs (http://misko.hevery.com/2008/11/17/unified-theory-of-bugs/)

: © Alexander MAZUROV, taxigy



translated.by








All Articles