当初テスト対象として設計されていなかったコードを、コードを変更せずに単体テストすることは可能ですか?

StackOverflow https://stackoverflow.com/questions/4033813

質問

コードがテスト用に設定されていない限り、コードをテストできないということは一般的に受け入れられていますか?

仮定のコード:

public void QueueOrder(SalesOrder order)
{
   if (order.Date < DateTime.Now-20)
      throw new Exception("Order is too old to be processed");
   ...  
}

これを次のようにリファクタリングすることを検討する人もいるでしょう。

protected DateTime MinOrderAge;
{
   return DateTime.Now-20;
}

public void QueueOrder(SalesOrder order)
{
   if (order.Date < MinOrderAge)
      throw new Exception("Order is too old to be processed");
   ...
}

注記: さらに複雑な解決策を思いつくこともできます。関係する IClock インターフェースとファクトリー。それは私の質問には影響しません。

上記のコードを変更する場合の問題は、コードが変更されていることです。お客様から変更を依頼されずにコードが変更されました。そして、どんな変化にも会議や電話会議が必要です。そのため、私は何もテストしないほうが簡単だと思うようになりました。

変更する気がない/変更できない場合:テストを実行できなくなりますか?

注記: 上記の疑似コードは C# のように見えるかもしれませんが、それは読みやすいようにするためだけです。質問は言語に依存しません。

注記: 仮説的なコード スニペット、問題、リファクタリングの必要性、およびリファクタリングは仮説的なものです。私の意見に不満がある場合は、独自の仮説コード サンプルを挿入できます。

注記: 上記の仮説的なコードは仮説的なものです。生きているか死んでいるかにかかわらず、コードとの関係はまったくの偶然です。

注記: コードは仮説ですが、答えは仮説ではありません。質問は主観的なものではありません。答えがあると信じているからです。


アップデート: ここでの問題は、もちろん、上記の例の変更によって何も壊れなかったという保証ができないことです。確かに、1 つのコードを別のメソッドにリファクタリングしましたが、そのコードは論理的には同じです。

ただし、新しい保護されたメソッドを追加しても影響がなかったとは保証できません オブジェクトの仮想メソッド テーブルのオフセット, 、このクラスが DLL 内にある場合、アクセス違反が導入されただけです。

役に立ちましたか?

解決

答えは「はい」です。テスト可能にするには、一部のコードを変更する必要があります。

しかし、変更せずにテストできるコードはたくさんあると思われます。私は、最初にその部分のテストを書くことに集中し、その後、他の顧客の要件によってテスト可能な方法でリファクタリングする機会が与えられたときに、残りの部分のテストを書くことにします。

他のヒント

最初からテスト可能なコードを作成できます。最初からテスト容易性を念頭に置いて書かれていない場合でも、テストすることはできますが、問題が発生する可能性があります。

仮説のコードでは、はるか過去の日付を使用して SalesOrder を作成して元のコードをテストしたり、DateTime.Now を模擬したりすることができます。示したようにコードをリファクタリングすると、テストには適していますが、絶対に必要というわけではありません。

コードがテストされるように設計されていない場合、テストはさらに困難になります。あなたの例では、DateTime.Now メソッドをオーバーライドする必要がありますが、これはおそらく簡単な作業ではありません。

コードにテストを追加したり、既存のコードの変更が許可されていない場合には、テストを追加する価値はほとんどないと思われる場合は、実行しないでください。

ただし、TDD を信じている場合は、テストを含む新しいコードを作成する必要があります。

モック オブジェクト フレームワークを使用して、元の例を単体テストできます。この場合、SalesOrder オブジェクトを数回モックし、毎回異なる Date 値を構成してテストします。これにより、出荷されるコードの変更が回避され、問題のアルゴリズムが注文日が過去のものではないことを検証できます。

扱っている依存関係と自由に使える言語機能を考慮して何が可能なのかをよりよく全体的に把握するには、以下をお勧めします。 従来のコードを効果的に使用する.

これは、一部の動的言語では簡単に実現できます。たとえば、SUT (テスト対象システム) が暗黙的な依存関係として使用している場合でも、import/using ステートメント内でフックして実際の依存関係をスタブ依存関係に置き換えることができます。あるいは、それらのシンボル (クラス、メソッド、関数など) を再定義することもできます。これがやり方だと言っているわけではありません。物事はリファクタリングする必要がありますが、いくつかの特性評価テストを作成する方が簡単です。

この種のコードの問題は常に、多くの静的クラス、フレームワーク タイプなどを作成し、それらに依存していることです。等...

これらすべてのオブジェクトに偽物を「注入」するための非常に優れたソリューションは、Typemock Isolator (商用ですが、1 ペニーの価値があります) です。はい、確かにあなたは できる テスト容易性を考慮せずに書かれたレガシー コードをテストします。私は Typemock を使って大きなプロジェクトでそれを実行し、非常に良い結果を得ました。

Typemock の代わりに、基本的に同じことを行う無料の MS Moles フレームワークを使用することもできます。ただ、API が非常に直感的ではなく、学習と使用がはるかに困難です。

HTH。
トーマス

Mockito + Mockito 用の PowerMock。

コードを大幅に変更することなく、ほぼすべてをテストできるようになります。ただし、モックを注入するにはいくつかのセッターが必要になります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top