2016-09-06 10 views
2

私は他人のコードの単体テストを書いていますが、これは変更できません。C#でインタフェースを持たず仮想メソッドを持たないクラスを模擬する方法は?

は、私が持っていると言う:で使用されて

class BadClass 
{ 
    public BadClass() 
    { 
     // the service isn't going to be running during testing 
     // it also has no interface 
     someFlag = AGloballyStoredService.getSomeFlag(); 
    } 

    public bool someFlag; 

} 

:私はBadClassを模擬したい

public void AnotherBadClassConstructorTest() 
{ 
    BadClass badClass = new BadClass(); 
    AnotherBadClass anotherBadClass = new AnotherBadClass(badClass); 
    Assert.IsNotNull(anotherBadClass); 
} 

が、それはあります

class AnotherBadClass 
{ 
    public AnotherBadClass(BadClass badClass) 
    { 
     someFlag = badClass.someFlag; 
    } 
    public bool someFlag; 
} 

は、私がテストをしたいと言いますインタフェースがなく、サービスが実行されていない場合は、そのコンストラクタで失敗します。

私がテストしているコードを変更できないことを考慮して、この作業を行う簡単な方法はありますか?

私は、既存のコードベースを修正するか、このモジュールの10%未満のカバレッジを受け入れる必要があることを伝えることができます。

+2

[Microsoft Fakes](https://msdn.microsoft.com/en-us/library/hh549175.aspx)のような特殊なライブラリを使用して、それらをリダイレクトする方法をインターセプトして書き直す必要がありますあなたのモック。 –

+1

コードに触れることができないのであれば、ここでは統合テストだけが実際にはオプションになるのではないかと思います。 –

答えて

4

私がテストしてるのコードを変更することはできませんことを考えると、この作品を作るための 簡単な方法はありますか?

A)ライブラリを書き換えることでモックを提供するために、Microsoft Fakesを使用します。

号しかし、私は2つ、非直接的なオプションを参照してください。コードを変更する必要はありません。例:あなたがテストしたクラスを継承して使用される方法/ ctorsを上書きしようとすることができます)

System.Fakes.ShimDateTime.NowGet = 
() => 
{ return new DateTime(fixedYear, 1, 1); }; 

B:あなたはこのようなあなたの好みの日付を返すために、静的DateTime.Nowを変更することができます。しかし、2つの制限があります。テストされたクラスのインスタンスをモックオブジェクトでインスタンシエート/スワップすることができなければなりません(リフレクションをプライベートメンバに渡すことによって)。モックされたメソッドは仮想でなければなりません。あなたの場合は、次のように作成します:

class BadClassMock : BadClass 
{ 
    public BadClassMock() 
    { 
    } 

    public bool someFlag; 

    public void InitForTest() 
    { 
     someFlag = true; 
    } 
} 

基本コンストラクタを呼び出さない限り、動作します。 Creating instance of type without default constructor in C# using reflection

以降:

public void AnotherBadClassConstructorTest() 
{ 
    BadClassMock badClassMock = (BadClassMock)FormatterServices.GetUninitializedObject(typeof(BadClassMock)); 
    badClassMock.InitForTest(); 
    AnotherBadClass anotherBadClass = new AnotherBadClass(badClassMock); 
    Assert.IsNotNull(anotherBadClass); 
} 

はい、それはかなり大きな回避策ですあなたはここからトリック)厄介なFormatterServices.GetUninitializedObjectを(使用することができます。明らかに、最良の方法は、コードを変更するように作者に納得させることです。

+0

それはうまくいくかもしれませんが、私がフェイクを持ち込むことができないかもしれないように見えます。 Moqに類似の機能があるかどうかは知っていますか? – Damien

+0

Moqはさまざまなレベルで動作します。 Moqでは、継承、仮想メソッド、またはインタフェースを使用してモックを作成できます。コンパイルされたコードでは動作しません。したがって、BadClassをモックすることはできません。 Fakeでは、BadClassのコンパイル済みコードを必要なものに交換するだけです。 Bオプションを試すことはできます。 – piotrwest

0

実際にを使用すると、コードを変更せずにBadClassをモックできます。仮想クラスでもインターフェイスでもクラスをモックできます。

[TestMethod] 
public void CreateAnotherBadClass_IsNotNull() 
{ 
    var fakeBadClass = Isolate.Fake.Instance<BadClass>(); 
    var anotherBadClass = new AnotherBadClass(fakeBadClass); 

    Assert.IsNotNull(anotherBadClass); 
} 

私はBadClassの偽のインスタンスを作成し、AnotherBadClass c'torに、それをパラメータとして送信され、この試験で:ここで例えば は、作成しようとしたテストです。

+0

この機能はTypeMock Isolatorで支払われることを追加する必要があります... – piotrwest

0

インターフェイスで取り込むコードを変更したくない場合は、TypeMockまたはJustMockのいずれかを使用して、これを擬似します。どちらも有料のツールであり、私はあなたがしたいことをすることができる無料のツールをまだ見つけていません。私はJustMockが好きです。 JustMockの構文はそうのようになります。あなたはこの多くをやっていくか、心の中でユニットテストを書かれていませんでしたレガシーコードをテストするために欠けている場合は

public void AnotherBadClassConstructorTest() 
{ 
    BadClassMock badClassMock = Mock.Create<BadClassMock>(); 
    AnotherBadClass anotherBadClass = new AnotherBadClass(badClassMock); 
    Assert.IsNotNull(anotherBadClass); 
} 

これらのツールはでコストも価値がある、私の意見。無料試用版をいつでも試すことができます。

関連する問題