web-dev-qa-db-ja.com

別のメソッドを呼び出すメソッドの単体テスト

複数のメソッドを呼び出すメソッドを単体テストする最良の方法は何ですか。次に例を示します。

_modify(string value)
{
    if(value.Length > 5)  replaceit(value);

    else changeit(value);
}
_

この疑似コードには、(現在)replaceit()またはchangeit()を呼び出す変更メソッドがあります。私はすでにreplaceitchangeitのテストを作成したので、変更用の新しいテストを作成すると、同じコードセットの99%になります。将来変更される可能性があるので、テストしてみました。

では、既存のテストコードをコピーして貼り付けますか?テストコードを一般的な関数に移動しますか?他のアイデアは?ここでのベストプラクティスはわかりません。

52
NotDan

これは、従来の状態ベースのテストと動作ベースのテストのシナリオです。

この途方もなく単純な例では、出力のテストで問題ありません。ただし、ある時点で、実行後の状態の検査が複雑なテストに遭遇します。代わりに、動作を確認します(たとえば、changeitが特定の値で呼び出されたことを確認します)。

その時点で、Rhino.Mocks(.Net)やMockito(Java)などのモックオブジェクトフレームワークを調べて、インターフェイスベースのコードの作成を開始する必要があります。

36
Eric Nicholson

いくつかのオプションがあります。どちらが最適かは、質問から明確ではない詳細に依存します。

  • modifyを、無関係なメソッドであるかのようにテストします。利点:ある時点で1つになる可能性があります。
  • ifステートメントが正しいことをテストしてください。つまり、テストで必要な実装を作成するように十分にテストします(replaceitおよびchangeitの呼び出しはおそらく機能する最も単純な実装です)。 TDDを実践している場合、これは自然に思いつくはずです。
  • サブクラスとオーバーライドメソッド(これは、本「レガシーコードを効果的に使用する」の依存関係を壊す手法です):replaceitchangeitに定型の回答を含めるか、センシング変数(メソッドが正しい値で呼び出されたかどうかを示す変数)を設定します。利点:テストを単純化する可能性があります(そうでない場合もあります)。
  • replaceitおよびchangeitメソッドの新しいクラスを、そのクラスのインターフェースを含めて抽出します。 modifyをテストするときに、そのインターフェイスをスタブまたはモックします。利点:どちらの方法でも、設計をよりテストしやすくなる可能性がありますおよび一般的に分離/再利用可能(またはそうでない)。
15
Ilja Preuß

replaceit()changeit()を個別にすでにテストしている場合、テストする必要があるのはif条件だけです。いくつかの値を使用してmodify()をテストし、適切な条件(nullおよびStringsの長さが4、5、および6の条件)で適切な関数を呼び出すことを確認します。あなたが与えたサンプルコード)。

15
Bill the Lizard

modifyをテストしてください。

Modifyは、特定の値を指定すると特定の値を返すことになっています。

それは重要ではない方法変更はその仕事をする-それだけ行うその仕事。

また、将来的にmodifyを変更して別のメソッドを使用する(またはメソッドを使用しない)場合、テストに影響はなく、また、影響しないはずです。

そうは言っても、テストreplaceit' andchangeit`。

6
Ian Boyd

優先順に

  1. modify(test)には2つのシナリオ(if stmtの各アーム)しかないため、フォームの変更用に2つのテストを記述します。
    replaceit(value)の期待される結果を簡単に判断できる場合。

public TestModifyIfValueLength..()
    {
      string expectedValue = .. ;// literal result of replaceit(value)
      Assert.Equals( expectedValue, modify("asd") );
    }
  1. そうでない場合は、スタブ(サブクラスを使用してchangeit、replaceitをオーバーライドする)を使用して、正しいメソッドが呼び出されたことを確認してください。
  2. スタブが多すぎる場合は、モックを実行します。インターフェイスを抽出し、changeit、replaceitに対する期待をセットアップします。

仮定

  • Replaceit(value)とchangeit(value)のテストがあり、これらの2つのメソッドを包括的にテスト(たとえば、すべての境界条件)します。
  • replaceit()およびchangeit()はパブリックメソッドです。そうでない場合は、パブリックメソッドに対してのみテストを作成することを検討してください。テストコードを知らなくても、プライベートメソッドを自由に調整/解放できます。
5
Gishu

この場合の「テストコード」とは何ですか?結果を設定して確認しますか?もしそうなら、私はそれを別のメソッドにリファクタリングし、各テストからそれを使用します。ただし、この方法のコードを読み取るだけで、テストが行​​うすべての内容を確認できることには、読みやすさというメリットがあります。

複雑なテスト方法は、最初に、正直に言うとしばしば煩わしくなります-多くの場合、それらは現実的に回避することはできませんが、can簡略化すると、価値がありますそうする。

4
Jon Skeet

いいえ、テストコードは99%同じではありません。実際には、replaceit、changeit、modifyがすべて同じ値を返さない限り、ここでは別のテストを行っています。

なぜ難しいのかわかりません。変更メソッドのテストは、約4行の長さである必要があります。基本的な機能を既にテストしていて、この特定のメソッドが壊れないことを確認するだけなので、この関数の2つの可能なコードパスをテストして期待値を返すテストを作成するだけで十分です。

2
TheSmurf

Replaceit()およびchangeit()のテストをすでに作成している場合、変更のテストは、 'value'の値に応じて異なる結果が返されることを確認するだけです。ただし、テストでメソッドのロジックを再実装するだけであり、これは少しばかげています。

この場合、より複雑なロジックになるまで、またはそれ以上の変更が行われるまで、変更をテストしません。テストにとってより重要な別のメソッドによって使用されます。

2
Eran Galperin

基本的に2つのテストが必要です。

1)「Quick Brown Fox Jumps!」のような文字列を渡します。 (長さが5を超える)は、値がreplaceit(...)の影響を受けることを確認します

2) "Foo"(長さが5未満)などの文字列を渡し、値がchangeit(...)の影響を受けることを確認します

テスト(疑似コード)は次のようになります。

testLongValue() {
    string testValue = "A value longer than 5 chars";
    string expected = "Replaced!";
    string actual = modify(testValue);
    assertEqual(expected, actual);
}

testShortValue() {
    string testValue = "len4";
    string expected = "Changed!";
    string actual = modify(testValue);
    assertEqual(expected, actual);
}

明らかに、replacit()とchangeit()が何をすることになっているのかを知っていれば、より現実的な例を示すことができますが、これはあなたにアイデアを与えるはずです。元の値参照を返すのではなく変更する場合は、呼び出しが発生した後で実際の値としてtestValueを使用できます。

2
Justin Standard

if (value.length > 5)のような境界条件をテストするときは、テストデータにvalueの長さ45、または6

2
Brian Matthews

メソッドからfuncを作成し、それらのfuncをモックすることができます。または、仮想メソッドを作成し、Rhinoモックを使用することもできます-部分的なモック、それらの仮想メソッドをモックすることができます。

2
Saravanan

ジャスティンスタンダードと同じplusnullを値として渡す(これは、指定したコードスニペットでは明らかに失敗します;))ユニットテストの基本ルールは、「テスト中のメソッド」。そして、別のメソッドを呼び出さないメソッドを持つことは珍しい...

0
Olivier