何も返さないメソッドを単体テストする最良の方法は何ですか?具体的には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つ目は少し注意が必要です。モック(モックフレームワークでグーグルまたは検索スタックオーバーフロー)を使用してDBを模倣するか、実際のDBにアクセスして、文字列が正しい場所に挿入されているかどうかを確認できます。このスレッドをチェックして良い本を探してください...もしあなたが危機に瀕しているなら、私はPragmatic Unit Testingを推薦します。
コードでは次のように使用されます
InsertStringsIntoDatabase( ExamineLogFileForX( "c:\OMG.log" ) );
その副作用をテストします。これも:
もちろん、テストできる量には制限があります。たとえば、すべての可能な入力でテストすることは通常できません。実用的にテストします。コードが適切に設計され、正しく実装されていることを確信するのに十分です。また、呼び出し元が期待するものの補足ドキュメントとして機能するのに十分です。
Voidの戻り値の型/サブルーチンは古いニュースです。(私が非常に怠惰でなかった場合を除いて)私はVoid戻り型を作成していません(この回答の時から、この質問がされる少し前)。
次のような方法の代わりに:
public void SendEmailToCustomer()
Microsoftのint.TryParse()パラダイムに従うメソッドを作成します。
public bool TrySendEmailToCustomer()
おそらく、長期的に使用するためにメソッドが返す必要のある情報がないかもしれませんが、ジョブの実行後にメソッドの状態を返すことは、呼び出し元にとって非常に役立ちます。
また、boolだけが状態タイプではありません。以前に作成されたサブルーチンが実際に3つ以上の異なる状態(Good、Normal、Badなど)を返すことができる場合がいくつかあります。そのような場合は、
public StateEnum TrySendEmailToCustomer()
ただし、Try-Paradigmは、ボイドリターンをテストする方法に関するこの質問にいくぶん答えますが、他の考慮事項もあります。たとえば、「TDD」サイクルの最中/後に、「リファクタリング」を行い、メソッドで2つのことを実行していることに気づくと、「単一の責任の原則」が破られます。最初にそれを処理する必要があります。次に、依存関係を無効にしている可能性があります...「永続的」データに触れています。
問題のメソッドでデータアクセスを行う場合は、n層またはn層のアーキテクチャにリファクタリングする必要があります。しかし、 "文字列がデータベースに挿入される"と言った場合、実際にはビジネスロジックレイヤーなどを呼び出すことを意味していると想定できます。そうだと思います。
オブジェクトがインスタンス化されると、オブジェクトに依存関係があることがわかります。これは、オブジェクトまたはメソッドに対して依存性注入を行うかどうかを決定する必要がある場合です。つまり、コンストラクタまたは問題のメソッドには新しいパラメータが必要です。
public <Constructor/MethodName> (IBusinessDataEtc otherLayerOrTierObject, string[] stuffToInsert)
ビジネス/データ層オブジェクトのインターフェースを受け入れることができるようになったので、単体テスト中にそれをモックアウトすることができ、依存関係や「偶発的な」統合テストの心配がありません。
したがって、ライブコードでは、REAL IBusinessDataEtc
オブジェクトを渡します。ただし、単体テストでは、MOCK IBusinessDataEtc
オブジェクトを渡します。そのモックint XMethodWasCalledCount
には、インターフェースメソッドが呼び出されたときに状態が更新されるような非インターフェースプロパティを含めることができます。
したがって、ユニットテストは、問題のメソッドを通過し、それらが持つロジックを実行し、IBusinessDataEtc
オブジェクト内の1つまたは2つ、または選択されたメソッドのセットを呼び出します。単体テストの最後にアサーションを実行すると、今テストすることがいくつかあります。
IBusinessDataEtc
オブジェクトの状態。構築レベルでの依存性注入のアイデアの詳細については、ユニットテストに関係するため、ビルダーの設計パターンを調べてください。現在のインターフェース/クラスごとにインターフェースとクラスが1つ追加されますが、これらは非常に小さく、ユニットテストを改善するために機能が大幅に向上しています。
public void sendEmailToCustomer() throws UndeliveredMailException
か?
void
方法、特にオブジェクト指向言語では、それが唯一の現実的な選択肢となっています。マイクロソフトによる最も古い代替手段は、私が議論するTry-Paradigmと、Monads / Maybesのような関数型のパラダイムです。したがって、コマンド(CQS内)は、スローに依存する代わりに、貴重なステータス情報を返すことができGOTO
ます。スロー(およびgoto)は遅く、デバッグが難しく、適切な方法ではありません。
これを試して:
[TestMethod]
public void TestSomething()
{
try
{
YourMethodCall();
Assert.IsTrue(true);
}
catch {
Assert.IsTrue(false);
}
}
ExpectedAttribute
より明確にこのテストを行うために設計されています。
次のように試すこともできます。
[TestMethod]
public void ReadFiles()
{
try
{
Read();
return; // indicates success
}
catch (Exception ex)
{
Assert.Fail(ex.Message);
}
}
おそらくメソッドは何かをして、単純に戻りませんか?
これが事実であると仮定すると、次のようになります。
その方法が何であるかを教えていただければ、もっと具体的にすることができます。
Rhino Mocksを使用して、予想される呼び出し、アクション、および例外を設定します。メソッドの一部をモックまたはスタブできると仮定します。メソッドやコンテキストについての詳細をここで知らずに知ることは困難です。
それが何をしているかによります。パラメータがある場合は、モックを渡して、後でパラメータの正しいセットを使用して呼び出されたかどうかを確認します。
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
テストが失敗するメソッドの失敗が原因で例外がスローされますか?