2013-05-14 8 views
17

में एक और विधि कहता है हाय मैं Moq ढांचे के लिए नया हूं और इसका उपयोग कैसे करें इसके बारे में कुछ प्रश्न हैं। मैं एक उदाहरण दूंगा और उत्तर के लिए आशा करूंगा।यूनिट परीक्षण में Moq का उपयोग कैसे करें जो एक ही कक्षा

public class Vehicle{ 
    public string RegistrationNumber {get; set;} 
    public long VehicleIdentifier { get; set; } 
    public Tyre TyreSpecification { get; set; } 
} 

public class Tyre { 
    public long NumberOfTyres {get; set;} 
    public long TyreSize { get; set;} 
} 

public interface ISelecter { 
    Vehicle GetVehicleByRegistrationNumber(string registrationNumber); 
    Tyre GetTyreSpecification(long vehicleIdentifier); 
} 

public class Selecter : ISelecter 
{ 
    public Vehicle GetVehicleByRegistrationNumber(string registrationNumber) 
    { 
     var vehicle = 'Database will give us the vehicle specification'; 

     //Then we do things with the vehicle object 

     //Get the tyre specification 
     vehicle.TyreSpecification = GetTyreSpecification(vehicle.VehicleIdentifier); 

     return vehicle; 

    } 

    public Tyre GetTyreSpecification(long vehicleIdentifier) 
    { 
     var tyre = 'external manufacture system gets the tyre specification'; 

     //Then do thing with the tyre before returning the object 


     return tyre; 
    } 
} 

मैं उन तरीकों के लिए दो परीक्षण लिखना चाहते हैं:

मैं दो वर्गों, एक अंतरफलक और और एक कार्यान्वयन है। समस्या तब होती है जब मैं GetVehicleByRegistrationNumber के लिए परीक्षण लिखता हूं, मुझे नहीं पता कि विधि कॉल को GetTyreSpecification पर कैसे मॉक करें।

परीक्षण तरीकों इस तरह दिखेगा:

[TestClass] 
public class SelecterTest 
{ 
    [TestMethod] 
    public void GetTyreSpecification_test() 
    { 
     //Arrange 
     var tyre = new Tyre { NumberOfTyres = 4, TyreSize = 18 }; 

     var mockSelecter = new Mock<ISelecter>(); 
     mockSelecter.SetUp(s=>s.GetTyreSpecification(It.IsAny<long>())).Returns(tyre); 

     //Act 
     var tyreSpec = mockSelecter.Object.GetTyreSpecification(123456); 

     //Assert 
     Assert.IsTrue(tyreSpec.NumberOfTyres == 4 && tyreSpec.TyreSize == 18); 
    } 

    [TestMethod] 
    public void GetVehicleByRegistrationNumber_test() 
    { 
     //Arrange 
     var vehicle= new Vehicle { VehicleIdentifier = 123456, RegistrationNumber = ABC123, TyreSpecification = new Tyre { Tyresize = 18, NumberOfTyres = 4 }}; 

     var mockSelecter = new Mock<ISelecter>(); 
     mockSelecter.SetUp(s=>s.GetVehicleByRegistrationNumber(It.IsAny<string> ())).Returns(vehicle); 

     //Act 
     var vehicle = mockSelecter.Object.GetVehicleByregistrationNumber(123456); 

     //Assert 
     Assert.IsTrue(vehicle.Registrationnumber == "ABC123"; 
    } 
} 

परीक्षा पद्धति GetVehicleByRegistrationNumber_test में मैं getTyreSpecification करने के लिए कॉल कैसे नकली हैं?

+0

@VSO द्वारा प्रदान किए गए उत्तर के बारे में कोई प्रतिक्रिया प्राप्त करने के साथ अपना यूनिट परीक्षण लिखना होगा? – Nkosi

+0

@ निकोसी हे नकोसी, अभी तक इसकी समीक्षा करने का कोई मौका नहीं है, मैं इसे एएसएपी देखूंगा। सामान्य रूप से मदद के लिए Ty! – VSO

+0

@Nkosi आपके परीक्षण अच्छे हैं! आपके द्वारा बताए गए परीक्षण से अधिक परीक्षण करने की कोशिश न करें - आपको रेग नंबर द्वारा वाहन प्राप्त करने से कहीं अधिक परीक्षण नहीं करना चाहिए। किसी भी वाहन विशिष्ट परीक्षणों को अपने स्वयं के परीक्षण विधियों में रखा जाना चाहिए जैसा आपने पहले ही लिखा है। एक समय में एक से अधिक चीजों का परीक्षण न करें। –

उत्तर

14

आपको जिस कक्षा में आप परीक्षण करने का प्रयास कर रहे हैं उस पर एक विधि का नकल करने की कोशिश नहीं करनी चाहिए। मॉकिंग फ्रेमवर्क का उपयोग उन निर्भरताओं पर किए गए वास्तविक कॉल को प्रतिस्थापित करने के लिए किया जाता है, जिन्हें आपकी कक्षा नकली कॉल के साथ ले जाती है ताकि आप अपनी निर्भरता से विचलित किए बिना अपनी कक्षा के व्यवहार का परीक्षण करने पर ध्यान केंद्रित कर सकें।

आपकी Selecter कक्षा द्वारा कोई बाहरी निर्भरता नहीं ली गई है, इसलिए आपको कुछ भी नकल करने की आवश्यकता नहीं है। यदि आप वास्तविक कोड को स्वयं परीक्षण और परीक्षण नहीं करते हैं तो मैं हमेशा मजाक नहीं करता हूं। जाहिर है, अपने परीक्षण परमाणु रखने के लिए, यदि कोई था तो आपको बाहरी निर्भरताओं पर कॉल करने की आवश्यकता होगी।

+0

मैं समझता हूं। लेकिन GetTyresSpecification में ऐसी चीजें हैं जिन्हें मैं निष्पादित नहीं करना चाहता हूं और जब मैं GetVehicleByRegistrationNumber का परीक्षण करता हूं यह वास्तविक अनुप्रयोग में समस्या का एक सरलीकृत संस्करण है, बाहरी सिस्टम को कॉल करने के लिए getTyreSpecification में किया जाता है। क्या इस विधि का नकल करना संभव नहीं है और केवल उस डेटा को पुनर्प्राप्त करना है जिसे मैं TyreSpecification के लिए चाहता हूं? – user2227138

+1

आपके पास 2 विकल्प हैं। आप या तो 'getTyreSpecification' विधि' के भीतर होने वाली बाहरी कॉल का नकल कर सकते हैं या आप उस विधि को अपने स्वयं के वर्ग में खींच सकते हैं, इंटरफ़ेस में लपेटा जा सकता है, और इंटरफ़ेस को अपने 'चयनकर्ता' वर्ग में इंजेक्ट कर सकता है। इससे आपको इसका मज़ाक उड़ाया जाएगा। – levelnis

+0

ठीक है आपके उत्तरों के लिए धन्यवाद। मैं बाहरी कॉल का मज़ाक उड़ाता हूं। इसका मतलब है कि मेरे पास GetTyresSpecification विधि के परीक्षण के लिए डुप्लिकेट कोड है। GetTyresSpecification विधि के लिए परीक्षण विधि में एक कोड स्निपेट और GetVehicleByregistrationNumber विधि में एक कोड स्निपेट जो एक ही चीज़ करता है। सही बात? – user2227138

0
var mockSelecter = new Mock<ISelecter>{ CallBase = true }; 
mockSelecter.SetUp(s=>s.GetTyreSpecification(It.IsAny<long>())).Returns(tyre); 
+3

कृपया अपने कोड का स्पष्टीकरण शामिल करने के लिए अपने उत्तर का विस्तार करें। –

+0

कॉलबेस का उपयोग करते समय आपको वास्तविक कक्षा का उपयोग करने की आवश्यकता नहीं है। इंटरफ़ेस की बेस क्लास को कॉल करना समझ में नहीं आता है। उपरोक्त विधि काम करेगी यदि वास्तविक वर्ग का उपयोग किया जा रहा है और विधि वर्चुअल है। – TehTechGuy

3

परीक्षण के तहत कक्षा का मज़ाक उड़ाते हुए ध्यान आपको वास्तविक समस्या के लिए अंधा कर दिया है।

परीक्षण के अंतर्गत कक्षा में टिप्पणियों से ...

'बाहरी निर्माण प्रणाली टायर स्पेसिफिकेशन हो जाता है' 'डाटाबेस हमें वाहन विनिर्देश दे देंगे'

आप वास्तव में दो निर्भरताओं का पर्दाफाश करते हैं जिन्हें कक्षा में इंजेक्शन दिया जाना चाहिए।

इस उत्तर को समझाने के उद्देश्य से कहें कि उन निर्भरताओं को इस तरह दिखता है।

public interface IDatabase { 
    Vehicle GetVehicleByRegistrationNumber(string registrationNumber); 
} 

public interface IExternalManufactureSystem { 
    Tyre GetTyreSpecification(long vehicleIdentifier); 
} 

यही मतलब यह होगा कि Selecter की आवश्यकता होगी उन निर्भरता की उम्मीद पुनर्संशोधित किया जाना है।

public class Selecter : ISelecter { 
    private IDatabase database; 
    private IExternalManufactureSystem externalManufactureSystem; 

    public Selecter(IDatabase database, IExternalManufactureSystem externalManufactureSystem) { 
     this.database = database; 
     this.externalManufactureSystem = externalManufactureSystem; 
    } 

    public Vehicle GetVehicleByRegistrationNumber(string registrationNumber) { 
     //'Database will give us the vehicle specification' 
     var vehicle = database.GetVehicleByRegistrationNumber(registrationNumber); 

     //Then we do things with the vehicle object 

     //Get the tyre specification 
     vehicle.TyreSpecification = GetTyreSpecification(vehicle.VehicleIdentifier); 

     return vehicle; 
    } 

    public Tyre GetTyreSpecification(long vehicleIdentifier) { 
     //'external manufacture system gets the tyre specification' 
     var tyre = externalManufactureSystem.GetTyreSpecification(vehicleIdentifier); 

     //Then do thing with the tyre before returning the object 

     return tyre; 
    } 
} 

वहां से यह केवल परीक्षण के तहत विधि के व्यवहार की जांच करने के लिए स्पष्ट रूप से आवश्यक निर्भरताओं का मज़ाक उड़ाएगा।

selecter.GetTyreSpecification डेटाबेस तक पहुंचने की कोई आवश्यकता नहीं है, इसलिए परीक्षण के लिए नकली और इंजेक्ट करने का कोई कारण नहीं है।

[TestMethod] 
public void GetTyreSpecification_test() { 
    //Arrange 
    var vehicleIdentifier = 123456; 
    var expected = new Tyre { NumberOfTyres = 4, TyreSize = 18 }; 

    var mockSystem = new Mock<IExternalManufactureSystem>(); 
    mockSystem.Setup(s => s.GetTyreSpecification(vehicleIdentifier)).Returns(expected); 

    var selecter = new Selecter(null, mockSystem.Object); 

    //Act 
    var actual = selecter.GetTyreSpecification(vehicleIdentifier); 

    //Assert 
    Assert.AreEqual(expected, actual); 
} 

selecter.GetVehicleByRegistrationNumber हालांकि अन्य विधि से टायर स्पेसिफिकेशन पाने के लिए तो यह परीक्षण दोनों निर्भरता क्रम में मज़ाक उड़ाया की आवश्यकता होगी यह पूरा करने के लिए प्रयोग किया जा करने में सक्षम होने की जरूरत है।

[TestMethod] 
public void GetVehicleByRegistrationNumber_test() { 
    //Arrange 
    var vehicleIdentifier = 123456; 
    var registrationNumber = "ABC123"; 
    var tyre = new Tyre { TyreSize = 18, NumberOfTyres = 4 }; 
    var expected = new Vehicle { 
     VehicleIdentifier = vehicleIdentifier, 
     RegistrationNumber = registrationNumber, 
     TyreSpecification = tyre 
    }; 

    var mockSystem = new Mock<IExternalManufactureSystem>(); 
    mockSystem.Setup(s => s.GetTyreSpecification(vehicleIdentifier)).Returns(tyre); 

    var mockDatabase = new Mock<IDatabase>(); 
    mockDatabase.Setup(s => s.GetVehicleByRegistrationNumber(registrationNumber)).Returns(expected); 

    var selecter = new Selecter(mockDatabase.Object, mockSystem.Object); 

    //Act 
    var actual = selecter.GetVehicleByRegistrationNumber(registrationNumber); 

    //Assert 
    Assert.IsTrue(actual.RegistrationNumber == registrationNumber); 
}  

अब जब कि रास्ते से बाहर के साथ, अगर उदाहरण के लिए Selecter वर्ग एक virtual पद्धति के रूप में GetVehicleByRegistrationNumber, था

public virtual Tyre GetTyreSpecification(long vehicleIdentifier) { 
    //...code removed for brevity. 
} 

वहाँ एक तरह से आप परीक्षण के अंतर्गत विषय ठूंठ moq का उपयोग कर सकते है और परीक्षण के लिए उस विधि नकली। यह हमेशा सबसे अच्छा डिजाइन नहीं होता है और इसे कोड गंध माना जाता है। हालांकि ऐसी स्थितियां हैं जहां आप इस विशेष परिदृश्य में समाप्त हो जाएंगे।

[TestMethod] 
public void GetVehicleByRegistrationNumber_test2() { 
    //Arrange 
    var vehicleIdentifier = 123456; 
    var registrationNumber = "ABC123"; 
    var tyre = new Tyre { TyreSize = 18, NumberOfTyres = 4 }; 
    var expected = new Vehicle { 
     VehicleIdentifier = vehicleIdentifier, 
     RegistrationNumber = registrationNumber, 
     TyreSpecification = tyre 
    };   

    var mockDatabase = new Mock<IDatabase>(); 
    mockDatabase.Setup(s => s.GetVehicleByRegistrationNumber(registrationNumber)).Returns(expected); 

    var selecter = new Mock<Selecter>(mockDatabase.Object, null) { 
     CallBase = true //So that base methods that are not setup can be called. 
    } 

    selecter.Setup(s => s.GetTyreSpecification(vehicleIdentifier)).Returns(tyre); 

    //Act 
    var actual = selecter.Object.GetVehicleByRegistrationNumber(registrationNumber); 

    //Assert 
    Assert.IsTrue(actual.RegistrationNumber == registrationNumber); 
} 

उपरोक्त उदाहरण में, जब selecter.Object.GetVehicleByRegistrationNumber(registrationNumber) कहा जाता है, आधार Selecter नकली द्वारा लपेटा, कहा जाएगा जो बारी में तो मज़ाक उड़ाया GetTyreSpecification कि परीक्षण के अंतर्गत मज़ाक उड़ाया विषय पर सेटअप द्वारा ओवरराइड होने कॉल करेंगे।

आप इसे देखने के लिए देखते हैं जब लागू सदस्यों के साथ सार वर्गों का परीक्षण करते हैं जिनके पास अमूर्त सदस्यों पर निर्भरता है।

+0

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

+0

स्पष्ट करें कि आप अधिक सामान्य शब्दों में क्या मतलब रखते हैं, इसलिए मैं इसे सीधे संबोधित कर सकता हूं। – Nkosi

+0

मेरा मतलब है कि इस प्रश्न के लिए विवरण के बजाय दृष्टिकोण का सामान्य विवरण। एक सामान्य उत्तर जिसे किसी भी उपयोग के मामले में लागू किया जा सकता है। अभी तक, आपने एक विशिष्ट उपयोग केस दिया है, और मुझे इसके सामान्य दृष्टिकोण को बाहर निकालना है, और फिर इसे मेरे उपयोग के मामले में लागू करना है। सामान्य दृष्टिकोण की व्याख्या करना बेहतर होगा। यदि आप चाहें तो केवल इसे ठीक करें।आपने अभी भी पहले से ही बक्षीस की मदद की और लायक है। – VSO

0

सामान्य रूप से हम सामान्य रूप से बाहरी निर्भरताओं/अन्य ऑब्जेक्ट/इंटरफ़ेस कॉल के लिए हमारे वर्ग के भीतर उपयोग किए जाने वाले मोक्स का उपयोग करेंगे जिसके लिए हम यूनिट परीक्षण लिखेंगे। तो जब आप अपने किसी एक फ़ंक्शन के लिए परीक्षण लिख रहे हैं जो आंतरिक रूप से उसी वर्ग के भीतर किसी अन्य फ़ंक्शन पर कॉल करता है तो आपको उस फ़ंक्शन कॉल को नकल करने की आवश्यकता नहीं होती है। हालांकि आंतरिक इंटरफ़ेस में यदि आप बाहरी इंटरफ़ेस पर कॉल कर रहे हैं तो आपको बाहरी इंटरफ़ेस उदाहरण का मजाक करना होगा और अपेक्षित परिणाम

संबंधित मुद्दे