2011-09-02 7 views
5

これは私の最初の質問ですので、親切にしてください! :)Moqを使用して戻り値のないメソッドをテストするには?

私がしようとしているのは、作成中に単一項目クラスの多くの新しいインスタンスをリストに追加するマネージャークラスのテストを書くことです。このマネージャクラスでUpdateAllItemsが呼び出されると、リストを反復して、各単一アイテムに対してIncrementを呼び出すことが意図されます。

マネージャークラスは私のコードですが、単一のアイテムクラスではありませんので変更できません。

私はテストフレームワークにNUnitを使用し、Moqを使い始めています。マネージャークラスは単一のアイテムクラスを使用するので、私はMoqを使う必要があると思うので、私はマネージャーだけをテストしているので、単一のアイテムではありません。

UpdateAllItemsメソッドのテストはどのように記述しますか? (技術的には私が最初に知っているテストを書くべきです)。ここで

は...すべての助けを事前に

public class SingleItem_CodeCantBeModified 
{ 
    public int CurrentValue { get; private set; } 

    public SingleItem_CodeCantBeModified(int startValue) 
    { 
     CurrentValue = startValue; 
    } 

    public void Increment() 
    { 
     CurrentValue++; 
    } 
} 

public class SingleItemManager 
{ 
    List<SingleItem_CodeCantBeModified> items = new List<SingleItem_CodeCantBeModified>(); 

    public SingleItemManager() 
    { 
     items.Add(new SingleItem_CodeCantBeModified(100)); 
     items.Add(new SingleItem_CodeCantBeModified(200)); 
    } 

    public void UpdateAllItems() 
    { 
     items.ForEach(item => item.Increment()); 
    } 
} 

おかげで私が働いているかの一般的なアイデアを与えるいくつかのサンプルコードです!

+0

このクラスはどのように役立ちますか?カウンタのプライベートリストを作成し、メソッドが呼び出されるたびに各項目を更新します。オブジェクトの振る舞いにはある程度の変更が必要です。 UpdateAllItemsが機能しない場合 - 変更はどのように観察されますか? – Gishu

答えて

5

簡単な答えはできません。 UpdateAllItemsが呼び出す方法(Increment())は仮想ではないため、あなたはそれをモックできません。

あなたのオプションは、私はそれを見るように、以下のとおりです。

  • は全くUpdateAllItemsをテストしないでください。その実装は自明なので、これは考慮するオプションです(理想的ではありませんが)。
  • テストで実際のSingleItem_CodeCantBeModifiedインスタンスを作成します。純粋な人はこの時点でユニットのテストがもうなくなったと言っていますが、まだ有効なテストになる可能性があります。
  • ISingleItemインターフェイスと、SingleItem_CodeCantBeModifiedへの参照を保持するSingleItemAdapter : ISingleItemクラスを追加し、コールを転送します。その後、SingleItemManagerと書いてISingleItemsで動作させることができます。テストではISingleItemの模擬試験をパスすることができます。 (お使いのシステムの設定方法に応じて、あなたも、SingleItem_CodeCantBeModifiedから降り、あなたの子孫にインターフェイスを実装し、アダプタを書くことでそれらのオブジェクトを代わりに使用することができるかもしれません。)

は最後のオプションは、あなた与えることほとんどのオプションは、しかし、いくつかの複雑さを犠牲にして。あなたが達成しようとしているものに最も適したオプションを選択してください。

1

あなたのマネージャーはアイテム(List<Item>)にあまり依存していません。あなたはそれを模擬できるように別のクラスにリストの人口を抽出することはできますか?例えば:

public SingleItemManager() 
{ 
    items.Add(ItemRepository.Get(100)); 
    items.Add(ItemRepository.Get(200)); 
} 

テスト(一部のコードは省略):

int i = 0; 

var itemMock = new Mock<Item>(); 
itemMock.Setup(i => i.Increment()).Callback(() => i++); 

var repositoryMock = new Moc<ItemRepository>(); 
repositoryMock.Setup(r => r.Get(It.IsAny<int>()).Returns(itemMock.Object); 

var manager = new SingleItemManager(); 
manager.UpdateAllItems(); 

Assert.AreEqual(i, 1); 
-1

の代わりにハードコーディング、あなたの追加の具体的な項目をSingleItem_CodeCantBeModifiedがインタフェースを実装している(またはインタフェースを実装ラッパーに埋め込みます)、これらのアイテムを作成する(新しい)ファクトリを渡します。

テストでは、Managerクラスに渡すファクトリのモックを作成し、そのモックされたオブジェクトでどのメソッドが呼び出されたかを監視できます。

これは、システムの内部をテストすることではなく、副産物をテストすることです。マネージャはどのインタフェースを実装していますか?それが外部からのものではない場合、どのような結果がテストされていますか?

+0

SingleItem_ ** CodeCantBeModified ** – riezebosch

+0

@riezebosch:プッシュが押された場合、インターファクトを実装したプロキシオブジェクトを作成し、メソッド呼び出しを渡すだけです。インターフェイスを実装するためにクラスを取得するのと全く同じことではありませんが、同じ効果があります。 – Chris

0

いつものように、別のレベルの間接参照を追加することができます。

  1. Incrementが仮想メソッドがある場合は、このラッパーはSingleItemManagerSingleItem_CodeCantBeModified

OR

の代わりにIItemに依存

  • くださいIItemインタフェースを継承させるSingleItem_CodeCantBeModified
  • のラッパークラスを作成します。私はあなたのサンプルコードではないことを理解していますが、ちょうどの場合)、partial mockingを使用してください。

  • 関連する問題