Moq

2009-08-18 16 views
18

के साथ बेस क्लास विधि कॉल का मज़ाक उड़ा रहा हूं, मैं एक क्लास विधि को संशोधित कर रहा हूं जो कुछ इनपुट पैरामीटर तिथियों को प्रारूपित करता है जिसे बाद में बेस क्लास (जो किसी अन्य असेंबली में रहता है) में विधि कॉल में पैराम्स के रूप में उपयोग किया जाता है।Moq

मैं यह सत्यापित करना चाहता हूं कि मेरी विधि में जो तिथियां पास की गई हैं वे सही प्रारूप में हैं जब वे बेस क्लास विधि में पास हो जाते हैं, इसलिए मैं बेस क्लास विधि कॉल को एमक करना चाहता हूं। क्या यह मोक के साथ संभव है?

उत्तर

12

अगर मैं आपके सवाल का सही ढंग से समझ, आप एक वर्ग एक कुछ अन्य विधानसभा में परिभाषित किया गया है, और फिर एक वर्ग बी और अधिक या कम इस तरह लागू किया:

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

और अब आप उस आधार सत्यापित करना चाहते हैं। MyMethod कहा जाता है?

मुझे नहीं लगता कि आप गतिशील नकली पुस्तकालय के साथ ऐसा कैसे कर सकते हैं। सभी गतिशील नकली पुस्तकालय (टाइपमॉक के निष्पादन के साथ) प्रश्न में टाइप किए गए वर्गों को गतिशील रूप से उत्सर्जित करके काम करते हैं।

आपके मामले में, तुम नहीं बहुत अच्छी तरह से Moq एक से प्राप्त करने, पूछने के बाद से आप बी परीक्षण करना चाहते हैं कर सकते हैं।

इसका मतलब है कि आपको Mock<B> देने के लिए आपको मक से पूछना चाहिए। हालांकि, इसका मतलब है कि उत्सर्जित प्रकार बी से निकला है, और जब यह MyMethod (जो अभी भी वर्चुअल है) को ओवरराइड कर सकता है और इसके आधार (बीएमएम विधि) को कॉल कर सकता है, तो उसके पास मूल वर्ग तक पहुंचने का कोई तरीका नहीं है और यह सत्यापित करें कि बी base.MyMethod पर कॉल करें । के संभावित अपवाद के साथ

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 
    } 
} 

फिर:

कल्पना कीजिए कि आप एक वर्ग (सी) कि बी से निकला है आप MyMethod ओवरराइड कर सकते हैं जबकि लिखने के लिए है, वहाँ कोई रास्ता नहीं है आपको लगता है कि बी ए कॉल की पुष्टि कर सकते है TypeMock, गतिशील नकली पुस्तकालय कुछ भी नहीं कर सकते हैं जो आप मैन्युअल रूप से नहीं कर सकते हैं।

हालांकि, मुझे लगता है कि आप जिस मूल विधि को सत्यापित करने की कोशिश कर रहे हैं उसे कॉल करना कुछ अवलोकन दुष्प्रभाव है, इसलिए यदि संभव हो, तो क्या आप विधि-आधारित परीक्षण के बजाय राज्य-आधारित परीक्षण का उपयोग कर सकते हैं ताकि विधि को कॉल करने के परिणाम को सत्यापित किया जा सके। ?

किसी भी मामले में, राज्य-आधारित परीक्षण अधिकांश मामलों में आपका डिफ़ॉल्ट दृष्टिकोण होना चाहिए।

1

मार्क के साथ सहमत हैं, यह 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बेसक्लास बढ़ाता है। BaseClass तरीकों है MethodA(), MethodB(), MethodC() ... DerivedClass इस विधि है: क्रम में मान्य करने के लिए

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

नकली आधार वर्ग के लिए आप चाहते हैं कि सभी MethodA(), MethodB(), MethodC()MyMethod() अंदर बुलाया जा रहा है।

आप DerivedClass में एक क्षेत्र बनाने के लिए: इसके अलावा एक विधि है, जो कर सकते हैं जोड़ने के

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

:

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

और यह भी आपके पास MyMethod() संशोधित करने के लिए इंजेक्ट करें। मॉक ऑब्जेक्ट

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

कंपाइलर त्रुटि: कीवर्ड 'यह' वर्तमान संदर्भ में उपलब्ध नहीं है। व्युत्पन्न वर्ग क्षेत्र में। –

7

2013 तक नवीनतम मोक के साथ आप कर सकते हैं। यहां एक 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 
}