昨年以上、私は最近読んだ本を使用して単体テストを学んでいます(== --- ==)The Art of Unit Testing、レガシーコードなどで効果的に機能します。ユニットテストやモックフレームワークなども定期的に使用しており、その価値を確実に理解しています。
ただし、状況が主に外部API呼び出しを使用することを余儀なくされているコードを要求するとき、私はまだTDD(TADとは対照的に)を心に抱くのに苦労しています。
サービス名を使用して、Windowsサービスに関連付けられているプロセスを取得します。
例:Function GetProcess(ByVal serviceName As String) As Process
System.Diagnostics.Process
)私が知る限り、設計には2つのアプローチがあります。
なぜこれをしたいのか理解できません(知的課題への対処は別として)。システムレベルのAPIを直接操作するこの種のコードは、TDDスタイルであるかどうかを問わず、単体テストが非常に困難であり、率直に言って、実際のプロジェクトで試すことはあまり価値がありません。
説明するタスクのほとんどは、適切なパラメーターを使用して適切な低レベルAPIメソッドを呼び出すことです。そして、残りのコード自体は非常に簡単なものかもしれませんが、専用インターフェースやモックオブジェクトなどの導入を必ずしも保証するものではありません。私は、全体が機能することをより高いレベルで検証するための統合テストを持つコンテンツでしょう。しかし、これはちょうど私の2セントです。
私にとってのユニットテストは、ルールブックや厳密な定義に従うことではありません。実際には、テストが「実際の」単体テストであるかどうかは気にしません。私のコードが自動化された繰り返し可能なテストでカバーされている限り、私は元気です。私は実用的なアプローチを好みます。
ユニットをシステムリソースから分離できないレベルがあります。 TDDを使用してシステムを開発するときは、その量のコードをできるだけ小さくし、可能な限り抑制します。この場合、IProcessManager
という概念から始めることができます。その概念は、GetProcess
および必要なその他のプロセス関連のメソッドを定義するインターフェースにすぎません。
interface IProcessManager {
Process GetProcess(string processName);
}
「なぜインターフェースなのか?」とあなたは尋ねます。インターフェイスはグローバル関数よりもモックしやすいからです。プロセスマネージャをモックする目的は、この関数を使用するすべてのコードが、発生する可能性のあるさまざまなエラー条件で適切に動作するようにすることです。指定された名前のプロセスがない場合はどうなりますか? processName
がnull
になるとどうなりますか? IProcessManagerのモック実装では、これらの条件を簡単に再現できます。
コインの反対側、期待する動作を実装する実際のプロセスは非常に明確に定義されており、問題は十分に封じ込められています。テストなしで実装を作成するか、少なくとも予測および制御できる条件のテストを作成できます。たとえば、実行時に現在実行中のプロセスの名前を検出できる場合、名前でProcess
を見つけるテストを作成できます。また、不正なプロセス名と存在しないものを思い付くことができるはずです。
単に正しくテストできない部分があることを理解してください。あなたは、物事がうまくいかない可能性を制限するためにあなたができることだけをすることができます。