2009-05-27 8 views
6

私はAddItemというOrderエンティティメソッドをテストしようとしています。重複したアイテムを追加できないようにしようとしています。ここではいくつかのサンプルコードは、次のとおりです。だからここユニットテストプライベートセッター質問(C#)

[Test] 
public void ItemCannotBeAddedTwiceToOrder() 
{ 
    Order o = new Order(); 
    Item i = new Item("Bike"); 

    o.AddItem(i); 
    o.AddItem(i); 

    Assert.AreEqual(o.ItemCount, 1, "A duplicate item was added."); 
} 

public void AddItem(Item newItem) 
{ 
    if(!CheckForDuplicateItem(newItem)) 
     _items.Add(newItem); 
} 

public bool CheckForDuplicateItem(Item newItem) 
{ 
    foreach(Item i in _items) 
    { 
     if(i.Id == newItem.Id) 
      return true; 
    } 

    return false; 
} 

は私の問題です:CheckForDuplicateItemメソッドが動作しますので、私は試験方法で新しい項目のプライベートセッターイドを設定するのですか?私は良いコーディング慣行のためにそのメンバーを公開させたくありません。私はちょうど愚かであり、エンティティアイテムにパブリックIdセッターを持たせる必要がありますか?または、反射を使用する必要がありますか?おかげ

注 - 私は通常、この目的のためにリフレクションを使用して永続

答えて

8

ためNHibernateはを使用しています。これは次のようになります。

typeof(Item).GetProperty("Id").SetValue(i, 1, null); 

ここで、1は、newItemインスタンスに設定するIDです。

私の経験では、ほとんどの場合、IDを設定する必要はありませんので、セッターをプライベートにしておく方が良いでしょう。ほとんどの場合、テストの目的でIDを設定する必要があります。単純にReflectionを使用します。

+0

おかげで多くのことを行ってもいいです。私はこれを試してみましょう。 – CalebHC

7

ご注文の動作を確認しているので、モックオブジェクトをアイテムとして使用することができます。 モックオブジェクトを使用すると、モックオブジェクトに何が起きるかのアサーションを定義し、それらをテストすることもできます。 この場合、アイテムごとに2つのモックオブジェクトを定義することができ、IDゲッターが呼び出され、ユニークな値を返すことが期待されます。次に、Orderビヘイビアをテストし、アイテムのidゲッターが呼び出されたかどうかを確認できます期待される。 私はRhino MocksをAyendeで使用することをお勧めします

+0

良い点。私は嘲笑して調べます。私はRhino Mockについてたくさんの良いことを聞いたことがあります。 – CalebHC

0

もう1つの解決策は、クラスから派生し、メンバーを派生クラスに公開することによってプライベートメンバーにアクセスできるようにすることです。テストにはかなりのオーバーヘッドがあり、Visual Studioにはbuild-in support for private methodsしかありません。

0

ここでは、ポイントが不足している可能性があります。あなたはDBへの複数の呼び出しを望まないので、複数の追加を避けていますか?私はNHibernateがあなたにそれを無料で与えると思います。あるいは、Setを使用する必要がありますか?アイテムが追加される場合と追加されない場合があるという呼び出し元にとっての意味は何ですか?

永続性の問題がない場合は、同じIDを持つ2つの異なる項目を追加して、最初のIDのみを持つことを確認できます。どのアイテムが注文に含まれているかを検出する方法がなければなりません。

3

Praveenの答えは正しいものであり、間違いなく一回の使用に間に合わず、これを強力なドメインモデル上で何度も繰り返しテストします。したがって、私はあなたがこのタイプの安全な呼び出しが値を設定することを可能にする拡張メソッドでそれを包み:あなたのテストアセンブリに

var classWithPrivateSetters= new ClassWithPrivateSetters(); 
classWithPrivateSetters.SetPrivate(cwps => cwps.Number, 42); 

ドロップこれを、あなたは

public static class PrivateSetterCaller 
{ 
    public static void SetPrivate<T,TValue>(this T instance, Expression<Func<T,TValue>> propertyExpression, TValue value) 
    { 
     instance.GetType().GetProperty(GetName(propertyExpression)).SetValue(instance, value, null); 
    } 

    private static string GetName<T, TValue>(Expression<Func<T, TValue>> exp) 
    { 
     MemberExpression body = exp.Body as MemberExpression; 

     if (body == null) 
     { 
      UnaryExpression ubody = (UnaryExpression)exp.Body; 
      body = ubody.Operand as MemberExpression; 
     } 

     return body.Member.Name; 
    } 
}