すべてにインターフェースがあります。テスト用の帽子をかぶるとき、私は特定の世界観を使ってテストを書きます。
- 何かが存在する場合、それを測定することができます。
- 測定できない場合は問題ありません。それが重要なのなら、私はまだそれを測定する方法を見つけていません。
- 要件は測定可能なプロパティを規定しているか、またはそれらは役に立たない。
- システムは、予期しない状態から、要件によって規定されている期待される状態に移行するときに、要件を満たします。
- システムは、サブシステムである可能性のある相互作用するコンポーネントで構成されます。すべてのコンポーネントが正しく、コンポーネント間の相互作用が正しい場合、システムは正しいです。
あなたの場合、あなたのシステムには3つの主要な部分があります:
- ファイルから初期化できるある種のデータまたは画像
- データを表示するメカニズム
- データを変更するメカニズム
ちなみに、これは元のModel-View-Controllerアーキテクチャとよく似ています。理想的には、これらの3つの要素は疎結合を示します。つまり、明確に定義された(したがって十分にテスト可能な)インターフェイスを使用して、これらの要素間に明確な境界を定義します。
ソフトウェアとの複雑な相互作用は、テストするシステムの要素の観点から表現できる小さなステップに変換できます。例えば:
データを含むファイルをロードします。グラフを表示します。UIでスライダーをドラッグすると、グラフがぐらつきます。
これは手動で簡単にテストでき、自動でテストするのは難しいようです。しかし、その話を私たちのシステムに翻訳しましょう:
- UIはファイルを開くメカニズムを提供します。コントローラーは正しいです。
- ファイルを開くと、コントローラーはモデルに適切なコマンドを発行します。コントローラーとモデルの相互作用は正しいです。
- テストファイルが与えられると、モデルはこれを予想されるデータ構造に解析します。モデルは正しいです。
- テストデータ構造が与えられると、ビューは予想される出力をレンダリングします。ビューは正しいです。一部のテストデータ構造は通常のグラフになりますが、他のグラフはぐらつきのあるグラフになります。
- インタラクションビューモデルが正しい
- UIには、グラフをぐらつくためのスライダーがあります。コントローラーは正しいです。
- スライダーを特定の値に設定すると、コントローラーは予想されるコマンドをモデルに発行します。コントローラーとモデルの相互作用は正しいです。
- ぐらつきに関するテストコマンドを受け取ると、モデルはテストデータ構造を期待される結果データ構造に変換します。
コンポーネントごとにグループ化すると、テストする次のプロパティが作成されます。
- モデル:
- ファイルを解析します
- ファイルを開くコマンドに応答する
- データへのアクセスを提供します
- make-wobblyコマンドに応答します
- 見る:
- コントローラ:
- ファイルを開くワークフローを提供します
- ファイルを開くコマンドを発行する
- ぐらつくワークフローを提供します
- make-wobblyコマンドの発行
- システム全体:
テストの問題を小さなサブテストに分解しないと、テストは非常に困難になり、非常に脆弱になります。上記のストーリーは、「特定のファイルをロードしてスライダーを特定の値に設定すると、特定の画像がレンダリングされる」として実装することもできます。これは、システム内の要素が変更されると壊れるため、壊れやすいものです。
- ぐらつきのコントロールを変更すると壊れます(たとえば、コントロールパネルのスライダーではなく、グラフのハンドル)。
- 出力フォーマットを変更すると壊れます(たとえば、グラフのデフォルトの色を変更したため、またはグラフをより滑らかに見せるためにアンチエイリアスを追加したため、レンダリングされたビットマップが異なります。どちらの場合でも注意してください)。
詳細なテストには、機能を壊すことを恐れずにシステムを進化させることができるという非常に大きな利点もあります。必要なすべての動作は完全なテストスイートによって測定されるため、何かが壊れた場合、テストによって通知されます。細かいので、問題のある領域を指摘します。たとえば、コンポーネントのインターフェイスを誤って変更した場合、そのインターフェイスのテストのみが失敗し、そのインターフェイスを間接的に使用する他のテストは失敗しません。
テストが簡単だと思われる場合は、適切な設計が必要です。たとえば、システム内のコンポーネントをハードワイヤードすると問題が発生します。コンポーネントとシステム内の他のコンポーネントとの相互作用をテストする場合、それらの他のコンポーネントをログに記録して確認できるテストスタブに置き換える必要があります。その相互作用を振り付けます。つまり、依存性注入メカニズムが必要であり、静的な依存関係は回避する必要があります。UIをテストする場合、このUIがスクリプト可能であると非常に役立ちます。
もちろん、そのほとんどは、すべてが切り離されて簡単にテスト可能で、飛んでいるユニコーンが愛と平和を広める理想的な世界の幻想にすぎません;-)根本的にテスト可能であるものはありますが、そうすることは非常に難しいことが多く、あなたの時間の使い方。ただし、システムはテストしやすいように設計できます。通常、テストに依存しないシステムでも、テストできる内部APIまたはコントラクトを備えています(そうでない場合は、アーキテクチャがおかしくて、大きな泥の玉を書いたと思います)。私の経験では、少量の(自動化された)テストでも、品質の顕著な向上に影響します。