何も返さないメソッドを単体テストする最良の方法は何ですか? 具体的にはC#で。
私が実際にテストしようとしているのは、ログ ファイルを取得して特定の文字列を解析する方法です。次に、文字列がデータベースに挿入されます。これまでに行われたことは何もありませんが、TDD には非常に新しいので、これをテストできるかどうか、または実際にテストされていないものかどうか疑問に思っています。
何も返さないメソッドを単体テストする最良の方法は何ですか? 具体的にはC#で。
私が実際にテストしようとしているのは、ログ ファイルを取得して特定の文字列を解析する方法です。次に、文字列がデータベースに挿入されます。これまでに行われたことは何もありませんが、TDD には非常に新しいので、これをテストできるかどうか、または実際にテストされていないものかどうか疑問に思っています。
メソッドが何も返さない場合は、次のいずれかです。
命令型メソッド - タスクが実際に実行されたかどうかを確認できます。状態の変更が実際に行われたかどうかを確認します。例えば
void DeductFromBalance( dAmount )
このメッセージの残高が実際に初期値よりも dAmount 少ないかどうかを確認することでテストできます
情報メソッド - オブジェクトのパブリック インターフェイスのメンバーとしてはまれです... したがって、通常は単体テストされません。ただし、必要に応じて、通知に対して行われる処理が行われるかどうかを確認できます。例えば
void OnAccountDebit( dAmount ) // emails account holder with info
電子メールが送信されているかどうかを確認することでテストできます
実際の方法について詳細を投稿すると、人々はより良い回答を得ることができます。
更新:あなたの方法は2つのことをしています。私は実際にそれを 2 つの方法に分割し、個別にテストできるようにしました。
string[] ExamineLogFileForX( string sFileName );
void InsertStringsIntoDatabase( string[] );
String[] は、最初のメソッドにダミー ファイルと予期される文字列を指定することで簡単に確認できます。2 つ目は少しトリッキーです。モック (モック フレームワークでの Google または検索スタック オーバーフロー) を使用して DB を模倣するか、実際の DB にアクセスして、文字列が正しい場所に挿入されたかどうかを確認できます。いくつかの良い本については、このスレッドを確認してください...困っている場合は、Pragmatic Unit Testingをお勧めします。
コードでは、次のように使用されます
InsertStringsIntoDatabase( ExamineLogFileForX( "c:\OMG.log" ) );
その副作用をテストします。これも:
もちろん、テストできる量には制限があります。たとえば、通常、考えられるすべての入力でテストすることはできません。実用的にテストする - コードが適切に設計され、正しく実装されているという確信を与えるのに十分であり、呼び出し元が期待するものに対する補足ドキュメントとして機能するのに十分です。
いつものように、メソッドが何をするのかをテストしてください!
どこかでグローバル状態を変更する必要がありますか (うーん、コードの匂い!)?
インターフェイスを呼び出す必要がありますか?
間違ったパラメーターで呼び出されたときに例外をスローする必要がありますか?
適切なパラメーターで呼び出されたときに例外をスローしないでください。
それは...?
これを試して:
[TestMethod]
public void TestSomething()
{
try
{
YourMethodCall();
Assert.IsTrue(true);
}
catch {
Assert.IsTrue(false);
}
}
無効な戻り値の型 / サブルーチンは古いニュースです。私は 8 年ほど (私が非常に怠け者でない限り) Void 戻り値の型を作成していません (この回答の時点から、この質問が尋ねられる少し前)。
次のようなメソッドの代わりに:
public void SendEmailToCustomer()
Microsoft の int.TryParse() パラダイムに従うメソッドを作成します。
public bool TrySendEmailToCustomer()
長期的に使用するためにメソッドが返す必要がある情報はないかもしれませんが、メソッドがジョブを実行した後にメソッドの状態を返すことは、呼び出し元にとって非常に役立ちます。
また、状態型は bool だけではありません。以前に作成されたサブルーチンが実際に 3 つ以上の異なる状態 (Good、Normal、Bad など) を返す場合が何度もあります。そのような場合、あなたはただ使うでしょう
public StateEnum TrySendEmailToCustomer()
ただし、Try-Paradigm は void リターンをテストする方法に関するこの質問にある程度答えていますが、他にも考慮事項があります。たとえば、「TDD」サイクル中/後に、「リファクタリング」を行っていると、メソッドで 2 つのことを行っていることに気付くでしょう。したがって、「単一責任の原則」を破っています。そのため、最初に対処する必要があります。第二に、依存関係を特定した可能性があります...「永続的な」データに触れています。
問題のメソッドでデータ アクセスを行っている場合は、n 層または n 層のアーキテクチャにリファクタリングする必要があります。しかし、「文字列がデータベースに挿入される」と言うとき、実際にはビジネス ロジック レイヤーか何かを呼び出していることを意味していると推測できます。ええ、私たちはそれを仮定します。
オブジェクトがインスタンス化されると、オブジェクトに依存関係があることがわかります。これは、依存性注入をオブジェクトに対して行うか、メソッドに対して行うかを決定する必要がある場合です。つまり、コンストラクターまたは問題のメソッドには新しいパラメーターが必要です。
public <Constructor/MethodName> (IBusinessDataEtc otherLayerOrTierObject, string[] stuffToInsert)
ビジネス/データ層オブジェクトのインターフェイスを受け入れることができるようになったので、単体テスト中にそれをモックアウトして、依存関係や「偶発的な」統合テストの恐れがなくなります。
したがって、実際のコードでは、REALIBusinessDataEtc
オブジェクトを渡します。しかし、ユニット テストでは、MOCKIBusinessDataEtc
オブジェクトを渡します。int XMethodWasCalledCount
そのモックには、インターフェイスメソッドが呼び出されたときに状態が更新されるような非インターフェイスプロパティを含めることができます。
したがって、単体テストは Method(s)-In-Question を通過し、それらが持つロジックを実行し、オブジェクト内の 1 つまたは 2 つ、または選択されたメソッドのセットを呼び出しIBusinessDataEtc
ます。単体テストの最後にアサーションを実行すると、テストすることがいくつかあります。
IBusinessDataEtc
オブジェクトの状態。構築レベルでの依存性注入のアイデアの詳細については、単体テストに関連するため、ビルダーの設計パターンを調べてください。現在のインターフェイス/クラスごとにインターフェイスとクラスを 1 つ追加しますが、それらは非常に小さく、単体テストを改善するために大幅な機能の増加を提供します。
それはオブジェクトに何らかの影響を与えます....効果の結果を照会します。目に見える効果がなければ、単体テストの価値はありません!
おそらく、メソッドは何かを行い、単純に返らないのでしょうか?
これが事実であると仮定すると、次のようになります。
メソッドの機能を教えていただければ、より具体的に説明できます。
Rhino モックを使用して、想定される呼び出し、アクション、および例外を設定します。メソッドの一部をモックまたはスタブ化できると仮定します。ここでメソッドやコンテキストについての詳細を知らずに知ることは困難です。
それが何をしているかに依存します。パラメーターがある場合は、適切なパラメーターのセットで呼び出されたかどうかを後で確認できるモックを渡します。