2013-05-23 6 views
6

「あなたのクラスをスタブしてSUT内で何が起こるかを制御する方法」に関する複数の答えを見ました。C#スタブ。すべてのテスト対象オブジェクトのインタフェース?

インターフェースを作成し、依存性注入を使用してそのインターフェイスを注入し、その後、SUTに注入、同じインタフェースを使用してスタブを作成します。

彼らは一つのことを言います。

しかし、私は私の以前の職場で学んだ:

あなたのユニットテストの場合は、すべてクラス/機能をテストします。

それは、特定の機能レイアウトを持っているすべてのクラスのためのインターフェイスを作成する必要があることを意味していますか?

これは、クラス/ファイルの量がちょうど約2倍になることを意味します。

以下の例に見られるように、これは「行く方法」ですか、私のユニットテストプロセスで何か不足していますか?

注: 私はVS2012 Expressを使用しています。つまり、「Faker」フレームワークを意味しません。私は、標準のVS2012ユニットテストフレームワークを使用しています。

非常に簡単な例として、SUTに渡された各インターフェイスをスタブすることができます。

IFoo.cs

public interface IFoo 
{ 
    string GetName(); 
} 

Foo.cs

public class Foo : IFoo 
{ 
    public string GetName() 
    { 
     return "logic goes here"; 
    } 
} 

IBar.cs:

public interface IBar : IFoo 
{ 
    IFoo GetFoo(); 
} 

Bar.cs:

public class Bar : IBar 
{ 
    public string GetName() 
    { 
     return "logic goes here"; 
    } 

    public IFoo GetFoo() 
    { 
     return null; // some instance of IFoo 
    } 
} 

IBaz.cs:

public interface IBaz 
{ 
    IBar GetBar(); 
} 

Baz.cs:に正しい方法で純粋主義の観点から、たぶん

public class Baz 
{ 
    public IBar GetBar() 
    { 
     return null; // some instance of IBar 
    } 
} 
+3

私のアドバイス:これらすべてのインターフェイスを作成する必要のない良い模擬フレームワーク(Moqは良い選択です)を見つけてください。 –

+0

私はそのフレームワークを見て行きます –

+1

@RobertHarvey:Moqはどのようにインターフェイスの作成を避けるために行くのですか? OPはまだそれが仮想メンバーかインタフェースかのそれ(Moq)のエントリーポイントを残す必要があります。 –

答えて

4

はい、いいえ。依存関係をスタブするには、抽象化が必要ですが、それはどのようにモックフレームワークwork(すべてではありません)のために大部分です。

単純な例を考えてみましょう。クラスAをテストすると、クラスBCに依存します。 Aの単体テストを動作させるには、BCをモックする必要があります。IBICまたは基本クラス/ w仮想メンバ)が必要です。 IAが必要ですか?いいえ、少なくともこのテストのためではありません。 Aが他のクラスに依存しない限り、を抽象化します。インタフェース/ ベースクラスは必須ではありません。

擬似結合コードを構築するのに役立つので、抽象化は優れています。依存関係を抽象化する必要があります。ただし、実際には、トップレベル/エンドオブ階層/ルートの役割を果たし、他の場所では使用されないため、いくつかのクラスを抽象化する必要はありません。

+0

だから、インターフェースを使う代わりに関数を仮想的にするために行くでしょう。これは不要な行動を余儀なくされますか?私は、クラスから継承し、すべてのメソッドをオーバーライドする子クラスを気にしません。 –

+0

@DaanTimmer:それはクラスごとに異なります。ただし、ほとんどの場合、インターフェイスを使用する必要があります。基本クラスと継承は、通常は把握するのが難しく、結果として構成よりも維持することが難しくなります([こちらを参照](http://en.wikipedia.org/wiki/Composition_over_inheritance))。もちろん、ベースクラスが正当化されるときには、それはあなたがすべきことです。もう一つのポイント - インターフェースに対するあなたの唯一の引数が "引数の倍数型"であれば、それはまったく引数ではありません。数値/統計の人為的な利益のために適切な設計を放棄するべきではありません。 –

+0

@DaanTimmer:さらに、そのような(メンバーを仮想化して)クラスを開くことは、まったく正当な理由がない場合(特に「少ないタイプ」が1つではない場合)は、まれです。 –

3

しかし、実際に重要なことは、外部依存関係(例:データベースアクセス、ネットワークアクセスなど)、計算コストが高く時間がかかるもの、完全に決定論的でないものはすべて抽象化され、ユニットテストで簡単に置き換えられます。

6

私の意見では、単なる単体テストのためにインターフェイスを作成すべきではありません。ツールを喜ばすためにコード抽象化を追加し始めたら、それらはあなたがより生産的になるのを助けるものではありません。あなたが書いたコードは、コードベースを容易に維持または発展させることによって、直接的または間接的に、特定のビジネス目的/ニーズに理想的に役立ちます。

インターフェイスでは時々これが行われますが、必ずしもそうではありません。私は、コンポーネントのインターフェイスを提供することは通常良いことだが、内部クラス(つまり、型がpublic宣言されているかどうかにかかわらず、指定されたプロジェクトの内部でのみ使用されるコード)のインターフェイスを使用しないようにしてください。これは、(特定の問題を解決するために一緒に働くクラスの集合のような)コンポーネントが、より大きな概念(ロガーやスケジューラなど)を表しているためです。これは、テスト時に置き換えたりスタブアウトしたりする可能性があります。

解決策(コメントの最初にあるRobertの帽子のヒント)は、実行時に互換性のある置換タイプを生成するために模造フレームワークを使用することです。 Mockingフレームワークでは、テスト対象のクラスが置換されたダミーと正しく対話しているかどうかを検証できます。 Moqは驚異的な選択肢として述べられています。 Rhino.MocksとNMockは、他の2つの一般的なフレームワークです。 Typemock Isolatorはプロファイラにフックし、より強力なオプションの1つです(非仮想プライベートメンバーでも置き換えることができます)が、商用ツールです。

単体テストをどのくらい行うべきかというルールを作るのは良いことではありません。それはあなたが開発しているものとあなたの目標が何であるかによって異なります。正確さが常に市場投入までに掛かり、コストが要因ではない場合、ユニットテストはすべて素晴らしいです。ほとんどの人は幸運ではなく、妥当なレベルのテストカバレッジを達成するために妥協しなければなりません。どのくらいテストする必要があるかは、チーム全体のスキルレベル、予想されるライフタイムとコードの再利用などによっても異なる場合があります。

+0

私は幸いなことに、マネージャーや製品の発売までに何の問題もありません。私は自分の仕事で(今のところ)学ぶことができない余分なものを誤って学ぶために私のフリータイムでこれを行う唯一の開発者です。 (埋め込まれたS.E.この時点でCを使用して、時にはアセンブリ、時にはC#、時々C + +)そうです。今私はちょうどC#のユニットテストに私の方法を見つけることです。以前はPython内でたくさんのユニットテストを行っていました(作業関連) –

0

テストの観点からは、コード。抽象化レイヤの背後にある外部依存関係の具体的な実行を非表示にするインターフェイスを作成します。したがって、直接HTTP接続がロジックと混在する必要のあるクラスを持つ代わりに、クラスに接続コードを分離し、クラスのメンバーであるインターフェイスを実装し、そのインターフェイスにモックを挿入します。こうすることで、ロジックを独立してテストすることができます。依存性がなく、「テストされていない」唯一のコードは、他の手段でテストできる定型的なHTTP接続コードです。

0

私は仮想メソッドルートに行きます。テストする必要のあるすべてのクラスのインターフェイスを作成することは、特にメソッドの定義を確認するたびに、「実装に移る」ためのResharperのようなツールが必要な場合は、非常に面倒です。また、メソッドシグネチャが変更されたり、新しいプロパティやメソッドが追加されたりすると、両方のファイルを管理および変更するオーバーヘッドが発生します。

関連する問題