2017-05-09 8 views
0

サードパーティのライブラリを照会するメソッドをテストしたいと考えています。ライブラリはIReadOnlyCollectionプロパティを持つオブジェクトを返します。モックメソッドの戻り値が読み取り専用のプロパティ

プロパティの値を設定するコンストラクタはありません。オブジェクトには私が偽装するためのインタフェースはありません。

私はMoqを使用して、私が呼び出したサービスのインターフェイスをモックしましたが、プロパティを設定できないので、私は偽の戻り値を作成できません。

public interface IHitService { 
    public Hit GetHit(); 
} 

public class Hit { 
    public Hit() { 
    } 

    public IReadOnlyCollection<string> Result { get; } 
} 

public class TestingClass { 
    public void MyTest() { 
     Hit hit = new Hit() { 
      // cannot set this property 
      Result = new List<string>() { "hello","goodbye" }; 
     } 

     Mock<IHitService> service = new Mock<IHitService>(); 
     service.Setup(c => c.GetHit).Returns(hit); 
    } 
} 

私のメソッドをテストするための戻り値を生成するにはどうすればよいでしょうか?ベースを隠すためにオブジェクトをnewプロパティで折り返しても機能しません。

+0

通常どのように設定されますか? –

+0

それが設定されていないかどうかは重要ですか?その第三者のもの。あなたは通常、自分のコードだけをテストしません –

+0

私がテストしている方法でデータを操作します。 'GetHit()'を呼び出し、 'Result'コレクションのデータを処理します。プロパティはもともとは 'IEnumerable'でしたが、最新のバージョンでは' ReadOnlyCollection'に変更されています。私はそれが図書館にどのように設定されているのか分かりません。それはいい考えです、私はソースコードをチェックします。 – hsimah

答えて

2

あなたは動作を変更することができますユニットテストフレームワークを使用することができますたとえば、この場合、Typemock Isolatorを使用して問題を解決しました。結果プロパティの戻り値を変更できるので、コードを変更したり、コードを追加することなくテストに「設定」することができます:

public void TestMethod1() 
{ 
    List<string> s = new List<string> { "sfas", "asfsa", "blbba" }; 
    var hit = Isolate.Fake.NextInstance<Hit>(); 

    Isolate.WhenCalled(() => hit.Result).WillReturnCollectionValuesOf(s); 
} 

このテストでは、私はHitクラスとResultプロパティの戻り値を作成した文字列のリストに変更しました。

1

あなたは、サードパーティのライブラリをテストする必要がある場合、あなた自身の抽象化(インターフェース)を作成し、テストと実際のコードの両方のためにそれに頼るより良いアイデアのようになります。アプリケーションで

public interface IHitService 
{ 
    IHit GetHit(); 
} 

public interface IHit 
{ 
    IReadOnlyCollection<string> Result { get; } 
} 

コードでは、具体的なサードパーティクラスに委任することによってIHitを実装する単純なラッパークラスを作成できます。これで、インターフェイスを必要に応じて嘲笑してテストすることができます。一般的に

+0

これは私の選択肢のようです。それは単純なクラスではありませんが、作業は完了する必要があります。御時間ありがとうございます。 – hsimah

+1

確かに、喜んで助けてください。これは、レベルが低すぎるとテストしているテストの匂いでもあります。多くの場合、ライブラリ呼び出しをテスト/モックするのではなく、ライブラリを消費する可能性のあるサービスインタフェースをテストする方が意味があります。 –

+0

ええ、これは「結果」に応じてさまざまなことが起こるため、入力オブジェクトを制御する必要があり、開発者が私のアクセスレベルを変更するという難しい状況です! – hsimah

1

、あなたはサードパーティのコードを変更することができない場合、それにアダプタを構築し、独自の抽象化を使用します -

public interface IHit 
{ 
    IReadOnlyCollection<string> Result { get; } 
} 

public interface IHitService 
{ 
    IHit GetHit(); 
} 

public class HitAdapter : IHit 
{ 
    private Hit _hit; 

    public HitAdapter(Hit hit) 
    { 
     _hit = hit; 
    } 

    public IReadOnlyCollection<string> Result => _hit.Result; 
} 


public class TestingClass 
{ 
    public void MyTest() 
    { 
     var hitMock = new Mock<IHit>(); 
     hitMock.Setup(c => c.Result).Returns<IReadOnlyCollection<string>>(x => new List<string>() {"hello", "goodbye"}); 
     var service = new Mock<IHitService>(); 
     service.Setup(c => c.GetHit()).Returns<IHit>(x => hitMock.Object); 
    } 
} 
+0

これは私の選択肢のようです。それは単純なクラスではありませんが、作業は完了する必要があります。御時間ありがとうございます。 – hsimah

+1

resharperをお持ちの場合は、委任アダプタの生成からロバの作業が多くなります –

関連する問題