208

何も返さないメソッドを単体テストする最良の方法は何ですか? 具体的にはC#で。

私が実際にテストしようとしているのは、ログ ファイルを取得して特定の文字列を解析する方法です。次に、文字列がデータベースに挿入されます。これまでに行われたことは何もありませんが、TDD には非常に新しいので、これをテストできるかどうか、または実際にテストされていないものかどうか疑問に思っています。

4

11 に答える 11

169

メソッドが何も返さない場合は、次のいずれかです。

  • 必須- オブジェクトにそれ自体に何かをするように要求しています..たとえば、状態を変更します(確認を期待せずに..それが行われると想定されています)
  • 情報提供- 何かが起こったことを (アクションや応答を期待せずに) 誰かに通知するだけです。

命令型メソッド - タスクが実際に実行されたかどうかを確認できます。状態の変更が実際に行われたかどうかを確認します。例えば

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" ) );
于 2008-10-29T07:39:52.050 に答える
67

その副作用をテストします。これも:

  • 例外はスローされますか?(必要な場合は、そうであることを確認してください。そうでない場合は、注意を怠ると発生する可能性のあるいくつかのコーナーケースを試してください-null引数が最も明白です。)
  • パラメータでうまく機能しますか?(変更可能な場合、変更すべきではないときに変更しますか?)
  • 呼び出しているオブジェクト/タイプの状態に適切な効果がありますか?

もちろん、テストできる量には制限があります。たとえば、通常、考えられるすべての入力でテストすることはできません。実用的にテストする - コードが適切に設計され、正しく実装されているという確信を与えるのに十分であり、呼び出し元が期待するものに対する補足ドキュメントとして機能するのに十分です。

于 2008-10-29T07:39:58.977 に答える
32

いつものように、メソッドが何をするのかをテストしてください!

どこかでグローバル状態を変更する必要がありますか (うーん、コードの匂い!)?

インターフェイスを呼び出す必要がありますか?

間違ったパラメーターで呼び出されたときに例外をスローする必要がありますか?

適切なパラメーターで呼び出されたときに例外をスローしないでください。

それは...?

于 2008-10-29T07:34:25.413 に答える
21

これを試して:

[TestMethod]
public void TestSomething()
{
    try
    {
        YourMethodCall();
        Assert.IsTrue(true);
    }
    catch {
        Assert.IsTrue(false);
    }
}
于 2016-05-12T07:47:27.413 に答える
13

無効な戻り値の型 / サブルーチンは古いニュースです。私は 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ます。単体テストの最後にアサーションを実行すると、テストすることがいくつかあります。

  1. Try-Paradigm メソッドになった「サブルーチン」の状態。
  2. モックIBusinessDataEtcオブジェクトの状態。

構築レベルでの依存性注入のアイデアの詳細については、単体テストに関連するため、ビルダーの設計パターンを調べてください。現在のインターフェイス/クラスごとにインターフェイスとクラスを 1 つ追加しますが、それらは非常に小さく、単体テストを改善するために大幅な機能の増加を提供します。

于 2014-05-30T16:47:38.103 に答える
6

それはオブジェクトに何らかの影響を与えます....効果の結果を照会します。目に見える効果がなければ、単体テストの価値はありません!

于 2008-10-29T07:30:33.160 に答える
4

おそらく、メソッドは何かを行い、単純に返らないのでしょうか?

これが事実であると仮定すると、次のようになります。

  1. 所有者オブジェクトの状態を変更する場合は、状態が正しく変更されたことをテストする必要があります。
  2. オブジェクトをパラメーターとして取り込んでそのオブジェクトを変更する場合は、オブジェクトが正しく変更されているかどうかをテストする必要があります。
  3. 特定のケースで例外がスローされる場合は、それらの例外が正しくスローされることをテストします。
  4. その動作がそれ自体のオブジェクトまたは他のオブジェクトの状態に基づいて変化する場合は、状態を事前に設定し、上記の 3 つのテスト メソッドのいずれかを使用して、メソッドが正しい I を持っているかどうかをテストします)。

メソッドの機能を教えていただければ、より具体的に説明できます。

于 2008-10-29T07:39:21.847 に答える
3

Rhino モックを使用して、想定される呼び出し、アクション、および例外を設定します。メソッドの一部をモックまたはスタブ化できると仮定します。ここでメソッドやコンテキストについての詳細を知らずに知ることは困難です。

于 2008-10-29T08:03:53.827 に答える
1

それが何をしているかに依存します。パラメーターがある場合は、適切なパラメーターのセットで呼び出されたかどうかを後で確認できるモックを渡します。

于 2008-10-29T07:33:02.140 に答える