2016-05-06 7 views
0

ユニットテスト:私のViewModelに使用されるモック静的クラスIのViewModel内の静的クラス(<code>MyStaticClass</code>)を使用しています

public class MyViewModel : ViewModelBase 
{ 
    public string MyProperty { get; set; } 

    //whatever... 

    public void FooMethod() 
    { 
     MyProperty = MyStaticClass.PropertyOne; 
    } 
} 

私の質問は:どのように私はMyViewModelユニットテストでMyStaticClassを模擬することができますか?

+1

MyStaticClassをいくつかのインターフェイスを実装する非静的クラスにラップすると、完了です。 – raven

+0

Gracias Roberto ;-)私はそれを –

答えて

1

単体テストを希望する場合は静的なクラスを使わないでください。ただし、静的なクラスを選択する必要がない場合は、単体テストのための動作を制御できます(厳密に言うとあざける!)DateTimeクラスは非常に便利なDateTime.Now静的メソッドが含まれていますが、ユニットテストので、「今」は常に変化している総痛みです。たとえば、

。これをラウンドするために、私はそれをラップする静的クラスを作成しました。

public static class SystemTime 
{ 
    private static DateTime _date; 

    public static DateTime Now => _date != DateTime.MinValue ? _date : DateTime.Now; 

    public static DateTime Today => _date == DateTime.MinValue ? DateTime.Today : _date.Date; 

    [Conditional("DEBUG")] 
    public static void Set(DateTime date) 
    { 
     _date = date; 
    } 

    public static void Reset() 
    { 
     _date = DateTime.MinValue; 
    } 
} 

これは、単体テスト用に操作できる静的クラスの例です。テストクラスのセットアップメソッドでは、SystemTimeを "Set"して常に必要な値を返すようにして、現在の時刻をテスト可能にするテストコードをテスト可能にすることができます。独自の静的クラスの重要な部分は、静的クラスを「テスト」状態でセットアップできるため、ユニットテストではある方法で動作しますが、リリースコードでは動作が異なります。

これを行うには、コードの機能を変更するために設定できるプロパティまたはメソッドを追加する必要があります。しかし、問題はありますが、それは静的なので一度設定すると設定されたままです。このラウンドを取得するには、クラスを元の状態に戻すことを絶対に忘れないでください。このコードをテストクラスのティアダウンメソッドに入れて、リセットするのを忘れることはありません。もう1つの問題は、導入するこれらのメソッドとプロパティが、非テストコードによって呼び出される可能性があるということです。これを避けるには、 "DEBUG"属性を設定するか、#if DEBUGブロックにテスト専用メソッド/プロパティをラップします。これは、開発中に誤ってプロパティを設定することを止めるものではありませんが、リリースビルドを壊して問題にフラグを立てます。このアプローチは慎重に使用してください!

EDIT:

私は非静的作ることができなかった静的なクラスを持っていたクラスが、私はこれを実装する静的クラスのラッパーを作成し、インターフェイスを作成することになり、上記簡単な例以上だった場合このインタフェースも実装されているモッククラスを使用します。私はコンストラクタ(私が好む)でクラスに渡すか、プロパティとして設定します。テストではモックバージョンを渡しますが、実際の実装ではラップバージョンで渡します。

+0

こんにちは。インタフェースを実装するサービスでこのクラスをラップし、それをIoCを使用してコンストラクタに挿入するとどうなりますか?それは良いでしょうか? –

+0

これは素晴らしいテクニックです。これを反映するように私の答えを更新しました。 –

+0

ありがとうございます。 –

1

私の質問は:私はMyViewModelユニットテストでMyStaticClassをモックできますか?

あなたの質問への答えは、単純な以上のものです:

あなたはすることはできません。あなたのコードからの静的がらくたの脱却たら

、あなたが戻ってテーブルにユニットテストを置くかもしれません。あなたは、アプリケーションの異なるクラスを具体的な依存関係から分離して単体テストすることについて考えるかもしれません。したがって、単体テストの前に、設計に少し時間を費やしています。はい、もちろん、あなたが過ごすことができますいくつかの先進的なユニットテストは、等...、正直なところ、支出いくつかのものを注入し、いくつかのコードを編んであなたのアセンブリを交換するように、実行時にいくつかのブードゥー教の魔法を行いますをフレームワークに$$$はよ長期的には設計にかかる時間がより収益性の高いアプローチになります。

しかし、あなたは思考の中にいくつかの時間を費やして適切ここにあなたのコードを設計するまで、あなたのコードカバレッジ向上させるために採用することができ安価なトリックです:で、その後

public class MyViewModel : ViewModelBase 
{ 
    internal static Func<string> MyPropertyInjector =() => MyStaticClass.PropertyOne; 

    public string MyProperty { get; set; } 

    //whatever... 

    public void FooMethod() 
    { 
     this.MyProperty = MyPropertyInjector(); 
    } 
} 

とは、あなたのunit test the friendly assembly

// arrange 
MyViewModel.MyPropertyInjector =() => "some expected value"; 

// act 
var sut = new MyViewModel(); 
sut.FooMethod(); 

// assert 
Assert.AreEqual("some expected value", sut.MyProperty); 

しかし、私は先に言ったように、それはあなたのコードカバレッジを向上させることにちょうどトリックですが、あなたはこのトリックは、あなたのコードの品質を向上していることを考えて、だまされてはいけないはずです。このためには、思考と設計にもう少し時間を費やす必要があります。

+0

のように言うでしょう、私はここで大きな問題はデザインだと思っています。そして、ビューモデルは他のクラスに依存する複雑なロジックを持っています。それはちょうどドメインモデルから事前に計算された値のダムコンテナでなければなりません – kai

+0

あなたの言葉をありがとう、ありがとう...インタフェースを実装するサービスでこのクラスをラップしてコンストラクタに注入するべきではないIoCを使って? –

+0

この隔離されたサービスは簡単に嘲笑されてテストされます。 –

0

あなたは、静的クラスをモックすることはできません。確定的な関数の作成以外は静的なクラスを避けることをお勧めします。例えばこの値を渡すと、常にこの値が返されます - ヘルパー関数などを考えます。データを操作または状態のいくつかの並べ替えに依存している

静的クラスをテストすることが極めて困難です。それ以外の場合は、この問題の軽減に役立つ静的クラス用のラッパーを作成できますが、おそらくラッパークラスをテストする問題にぶつかります。

+0

ありがとう@Kritner、私は最良のソリューションは、この静的クラスを外部サービスでラップし、ViewModelコンストラクタにIoCを使用して注入することだと思います。ありがとう。 –

関連する問題