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