2009-08-18 25 views
18

私はいくつかの入力パラメータ日付を書式設定するメソッドを変更しています。これはその後、(別のアセンブリに存在する)基本クラスへのメソッド呼び出しでパラメータとして使用されます。Moqを使って基本クラスメソッド呼び出しをモックする

私は自分のメソッドに渡す日付が、基本クラスのメソッドに渡されるときに正しいフォーマットであることを確認したいので、Moqの基本クラスのメソッド呼び出しにしたいと思います。これはMoqでも可能ですか?

答えて

12

私が正しくあなたの質問を理解していれば、あなたはいくつかの他のアセンブリで定義されたクラスAを持ち、その後、クラスBは、次のように多かれ少なかれ実装:

public class B : A 
{ 
    public override MyMethod(object input) 
    { 
     // Do something 
     base.MyMethod(input); 
    } 
} 

そして今、あなたはそのベースを検証したいです。 MyMethodは呼ばれていますか?

ダイナミックモックライブラリでこれを行う方法はわかりません。すべての動的モックライブラリ(TypeMockの例外付き)は、問題の型から派生したクラスを動的に出力することによって機能します。あなたはBをテストしたいので、あなたの場合は

は、あなたは非常によく、から派生する部品番号を求めることはできません。

これは、あなたにMock<B>を与えるようにMoqに依頼しなければならないことを意味します。しかし、これは、放出された型がBから派生し、MyMethod(まだ仮想です)を呼び出してその基底(B.MyMethod)を呼び出すことができますが、元のクラスに到達する方法がなく、Bがbase.MyMethod

あなたがMyMethodはを上書きすることができますがBから派生するクラス(C)を記述する必要があること、あなたはBを呼び出すことを確認することができます方法はありません想像:

の可能性を除いて再び
public class C : B 
{ 
    public override MyMethod(object input) 
    { 
     // How to verify that base calls its base? 
     // base in this context means B, not A 
    } 
} 

TypeMockでは、動的モックライブラリは手動で行うことができないアニメーションを実行できません。

しかし、私が検証しようとしているベースメソッドを呼び出すことには、観察可能な副作用があると思われます。可能であれば、ビヘイビアベースのテストの代わりに状態ベースのテストを使用して、 ?

いずれの場合でも、ほとんどの場合、状態ベースのテストがデフォルトのアプローチであるはずです。

1

Markと同意すると、Moqを使用することはできません。

あなたの状況によっては、swithcing from inheritance to compositionと考えることができます。その後、依存関係を模擬してメソッドを検証することができます。もちろん、場合によってはそれだけの価値がないかもしれません。

1

メソッドで基本クラスメソッドをラップし、そのメソッドを などに設定します。

public class B : A 
{ 
    public virtual BaseMyMethod(object input) 
    { 
     // Do something 
     base.MyMethod(input); 
    }  
public override MyMethod(object input) 
    { 
     // Do something 
     BaseMyMethod(input); 
    } 
} 

、今セットアップBaseMyMethod

0

私はこの解決策を見つけた - 醜いが、それは仕事ができます。

var real = new SubCoreClass();       
var mock = new Mock<SubCoreClass>(); 
mock.CallBase = true; 

var obj = mock.Object; 

mock 
    .Setup(c => c.Execute()) 
    .Callback(() => 
     {                  
     obj.CallBaseMember(typeof(Action), real, "Execute");    
     Console.WriteLine(obj.GetHashCode()); 
     } 
    ); 

public static Delegate CreateBaseCallDelegate(object injectedInstance, Type templateDelegate, object instanceOfBase, string methodName) 
{ 
    var deleg = Delegate.CreateDelegate(templateDelegate, instanceOfBase, methodName); 
    deleg.GetType().BaseType.BaseType.GetField("_target", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(deleg, injectedInstance); 

    return deleg; 
} 

public static object CallBaseMember(this object injectedInstance, Type templateDelegate, object instanceOfBase, string methodName, params object[] arguments) 
{ 
    return CreateBaseCallDelegate(injectedInstance, templateDelegate, instanceOfBase, methodName).DynamicInvoke(arguments); 
} 
3

モックベースクラスがかなり可能です。しかし、ターゲットクラスを変更する必要があります。

例:DerivedClass extend BaseClassBaseClassのはDerivedClassは、このメソッドを持っている方法MethodA()MethodB()MethodC() ... があります

void MyMethod() { 
    this.MethodA(); 
    this.MethodB(); 
    this.MethodC(); 
} 

あなたが検証するために、基本クラスをモックとしたいですすべてMethodA()MethodB()こと、MethodC()MyMethodは()内部で呼ばれています。

あなたはDerivedClassでフィールドを作成する必要があります。また、することができる方法を、追加

void MyMethod() { 
    self.MethodA(); 
    self.MethodB(); 
    self.MethodC(); 
} 

MyMethodは()を変更する

class DerivedClass { 
    private BaseClass self = this; 
    ... 
} 

そしてまた、あなたが持っていますthis.selfフィールドをMockオブジェクトに挿入する

public void setMock(BaseClass mock) { 
    this.self = mock; 
} 

今、あなたはモックことができます。この技術を使用して

DerivedClass target = new DerivedClass(); 
BaseClass mock = new Mock(typeof(BaseClass)); 
target.setMock(mock); 
target.MyMethod(); 

mock.verify(MethodA); 
mock.verify(MethodB); 
mock.verify(MethodC); 

、あなたはまた、ネストされたメソッド呼び出しを模擬することができます。

+0

コンパイラエラーがあります。キーワード 'this'は現在のコンテキストでは使用できません。 [派生クラス]フィールド。 –

7

2013年現在、最新のMoqを使用できます。ここにはexample

public class ViewModelBase 
{ 
    public virtual bool IsValid(DateTime date) 
    { 
     //some complex shared stuff here 
    } 
} 

public class MyViewModel : ViewModelBase 
{ 
    public void Save(DateTime date) 
    { 
     if (IsValid(date)) 
     { 
      //do something here 
     } 
    } 
} 

public void MyTest() 
{ 
    //arrange 
    var mockMyViewModel = new Mock<MyViewModel>(){CallBase = true}; 
    mockMyViewModel.Setup(x => x.IsValid(It.IsAny<DateTime>())).Returns(true); 

    //act 
    mockMyViewModel.Object.Save(); 

    //assert 
    //do your assertions here 
}