2014-12-18 6 views
7

मैं शीर्षक में तीन घटकों को संयोजित करने वाली चीजों को व्यवस्थित करने के तरीके के बारे में बहुत सारे दस्तावेज और उदाहरण पढ़ रहा हूं। मैं अपने व्यापार तर्क पर एक विधि के लिए एक परीक्षण विधि के साथ आया, लेकिन यह बहुत घबराहट और गंदे लगता है।एक्सयूनीट, ऑटोफिक्स्चर और मोक सर्वश्रेष्ठ अभ्यास

मैं इस विषय पर अधिक अनुभवी लोगों से कुछ प्रतिक्रिया प्राप्त करना चाहता हूं यह देखने के लिए कि मैं इसे कैसे सुधार सकता हूं।

यहाँ कोड है, स्पष्टीकरण इस प्रकार है:

[Fact] 
public void ShouldGetItemWithSameId() 
{ 
    var fixture = new Fixture().Customize(new AutoMoqCustomization()); 
    var facade = fixture.Freeze<Mock<IDataFacade>>(); 
    facade.Setup(c => c.Get(It.IsAny<int>())).Returns((int i) => new Item { Key = i }); 

    var sut = fixture.Create<BusinessLogic>(); 
    var expected = fixture.Create<int>(); 

    Assert.Equal(expected, sut.Get(expected).Key); 
} 

मेरे BusinessLogic वर्ग निर्माता पैरामीटर, जो एक ही आईडी, सुंदर बुनियादी सामान के साथ आइटम को पुन: प्राप्त करने के लिए अपने Get(int) विधि में जिम्मेदार है के रूप में एक IDataFacade लेता है।

मैं IDataFacade नकली जमा करता हूं और मैंने इसे It.IsAny<int> में आईडी से मेल खाने वाली ऑब्जेक्ट बनाने के लिए सेट अप किया है। मैं फिर अपना एसयूटी बना देता हूं और इसका परीक्षण करता हूं। ठीक काम करता है।

मैं समझता हूँ कि अगर मैं पर विचार बातें सुधार कर सकते हैं करना चाहते हैं निम्नलिखित:

  • मैं और अधिक जटिल तरीकों, एक Query विधि है कि कि उपयोग किया जाएगा एक वर्ग गुण का एक बहुत युक्त लेता है की तरह का परीक्षण करने के लिए है पूछताछ के प्रकार पर मिलान गुणों पर फ़िल्टर के रूप में पूछताछ की जा रही है। इस मामले में मुझे नहीं पता कि नकली के "सेटअप" भाग को सही तरीके से कैसे करना है, क्योंकि मुझे सभी को प्रारंभ करना है, या सभी के करीब, लौटा प्रकार के गुण, और इस परिदृश्य में यह एक आइटम नहीं है लेकिन एक पूरी संग्रह
  • सेटअप हिस्सा जगह से बाहर लगता है, मैं और अधिक तरीकों

में यह पुन: उपयोग करने में सक्षम होना चाहते हैं मैं AutoMoqData साथ Theory का उपयोग कर कुछ अन्य परीक्षण है, लेकिन मैं इस परीक्षण को प्राप्त करने में असमर्थ था (और मुझे लगता है कि अधिक जटिल वाले) उस दृष्टिकोण का उपयोग करते हुए, इसलिए मैंने मैन्युअल रूप से तत्काल स्थिरता के साथ सादे Fact पर वापस स्विच किया।

किसी भी मदद की अत्यधिक सराहना की जाएगी।

+0

क्या आपने (ऑटो) एनएसयूबिस्टिट माना है - मैंने अपने 'मोक' के साथ गलत क्या है, अपमान रवैया बहुत लंबे समय तक किया। http://weareadaptive.com/blog/2014/09/30/why-nsubstitute/ –

उत्तर

5

आपका परीक्षण, मेरे लिए ठीक लग रहा है, हालांकि मैं एक परिवर्तन की सिफारिश करेंगे।निम्न पंक्ति केवल अप करने के लिए कड़ा किया जा सकता है उम्मीद मान यदि अपेक्षित मान पारित हो जाता है:

facade.Setup(c => c.Get(It.IsAny<int>())).Returns((int i) => new Item { Key = i }); 

आपको बस इतना करना होगा कि ऐसा तरह की उम्मीद चर ले जाएँ और Is.IsAny बदलने के लिए:

var expected = fixture.Create<int>(); 
facade.Setup(c => c.Get(expected)).Returns((int i) => new Item { Key = i }); 

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

मुझे नहीं लगता कि आपको लौटाए गए सभी मूल्यों को प्रारंभ करने की आवश्यकता होगी। मैं अनुमान लगा रहा हूं कि आपका डेटाफैक्ड एक ऑब्जेक्ट (या इस मामले में सूची) देता है? आपको बस इतना करना होगा कि ऑब्जेक्ट लौटाए गए डेटाफैक्ड से लौटे गए संदर्भों से मेल खाते हैं, आपको गुणों आदि के बारे में चिंता करने की आवश्यकता नहीं है क्योंकि आप उन वस्तुओं के निर्माण का परीक्षण नहीं कर रहे हैं, बस वे हैं लौटा हुआ। अगर मैंने गलत समझा है और आप बिजनेस लॉजिक में ऑब्जेक्ट्स का निर्माण कर रहे हैं तो यह एक अलग मामला है। व्यक्तिगत रूप से, मेरे पास डेटा परत पर निर्भर व्यावसायिक तर्क नहीं होगा लेकिन यह एक अलग चर्चा है। :-)

सेटअप हिस्सा जगह से बाहर लगता है, मैं और अधिक तरीकों

आप कर सकते हैं में यह पुन: उपयोग करने में सक्षम होना चाहते हैं। या तो इसे एक अलग विधि में निकालें या, यदि यह कक्षा में प्रत्येक परीक्षण के लिए लागू है, तो इसे एक सेटअप विधि में रखें। मैं XUnit से परिचित नहीं हूं लेकिन मैंने उपयोग किए गए हर दूसरे टेस्ट फ्रेमवर्क को सामान्य सेटअप करने की क्षमता प्रदान की है, इसलिए मुझे संदेह है कि XUnit कोई अलग होगा।

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

संपादित करें, यह पता चला है कि यह मेरी अंतिम टिप्पणी नहीं है! यदि आप टीडीडी के लिए नए हैं, जो मुझे यकीन नहीं है कि आप हैं, तो अपने आवेदन में प्रत्येक कक्षा का परीक्षण करने के जाल में न आएं, यह एक आम पैटर्न है जो प्रचलित हो गया है और यह मेरी राय में टीडीडी को कम करता है । मैंने blog post on my feelings लिखा है और इस मामले पर इयान कूपर ने superb presentation दिया है।

+0

ऑटोफिक्शन के निर्माण() में एक अच्छा छोटा रैपर है [tdd-toolkit] (https://github.com/grzesiek-galezowski/tdd-toolkit) तो 'var अपेक्षित = स्थिरता। () बनाएं;' 'var अपेक्षित = Any.Integer();' –

+0

@ रोबी-वाई रैपर एक खिंचाव का थोड़ा सा है; जबकि मुझे यकीन है कि इसकी जगह है, यह ओपी चाहता है सामान की ढेर को संबोधित नहीं करता है तो क्यों वाक्यविन्यास/सम्मेलन के दो सेटों के भ्रम का परिचय देते हैं। –

+0

@ रूबेनबार्टेलिंक आम तौर पर सहमत होते हैं, लेकिन कुछ मामलों में यह मुझे थोड़ा और स्पष्ट कोड प्राप्त करने में मदद करता है, शायद एक बेहतर उदाहरण है, उदाहरण के लिए, कोई भी। इंटेगरऑथरहान (42) जिसकी ज़रूरत नहीं थी - बस कुछ छोटी वाक्य रचनात्मक चीनी का सुझाव देना जो कभी-कभी सहायक हो सकता है, धन्यवाद –

2

कुछ मूल बातें:

आपका टेस्ट कक्षा instantiated है (और इसके निर्माता कहा जाता है) प्रत्येक एकल टेस्ट से पहले चलाया जाता है। जैसे अपने टेस्ट वर्ग के साथ [तथ्य] विशेषता है, यह तीन बार

एक TestFixture वर्ग एक और वर्ग है जो अपने परीक्षण कक्षा में सभी टेस्ट मैचों के लिए एक बार instanciated करने के लिए है है instantiated हो जाता है तीन तरीकों है या नहीं।

यह काम करने के लिए, आपकी परीक्षा कक्षा को IUseFixture इंटरफ़ेस को लागू करना होगा, उदा। एक सदस्य SetFixture()

लागू करें आप कई टेस्ट कक्षाओं के लिए एक ही MyTestFixture क्लास का उपयोग कर सकते हैं।

टेस्टफिक्चर के अंदर आप सभी नकली-सेटअप करते हैं।

यहाँ सामान्य लेआउट:

public class MyTestFixture 
{  
    public Mock<MyManager> ManagerMock; 

    public TestFixture() // runs once 
    { 
     ManagerMock.Setup(...); 
    } 
} 

public MyTestClass : IUseFixture<MyTestFixture> 
{ 
    private MyTestFixture fixture; 

    public MyTestClass() 
    { 
     // ctor runs for each [Fact] 
    } 

    public void SetFixture(MyTestFixture fixture) 
    { 
     this.fixture = fixture; 
    } 

    [Fact] 
    public void MyTest 
    { 
     // use Mock 
     fixture.ManagerMock.DoSomething() 
    } 
} 
+0

मुझे पहले से ही यह सब सामान पता है, लेकिन मुझे लगता है कि IUseFixture इंटरफ़ेस का उपयोग ऑटोफिक्चर होने के उद्देश्य को हरा देता है। हो सकता है मैं गलत हूं। –

+0

"टेस्टफिक्चर के अंदर आप सभी मॉक-सेटअप करते हैं" - मैं असहमत हूं, आपको केवल उस सेटअप को करना चाहिए जो उस स्थिरता में सभी परीक्षणों पर लागू हो। – DoctorMick

+0

@ डॉक्टर मिक हां, बेशक, टेस्टफिक्चर में आप केवल (केवल) सभी चीजों की आवश्यकता है ** ** सभी परीक्षण ** – DrKoch

7

कुल मिलाकर, मूल परीक्षण अच्छा दिखता है। एक सामान्य फैशन में परीक्षण से बाहर Stubs and Mocks के सेटअप को निकालना संभव नहीं है और न ही आसान है।

क्या आप कर सकते हैं, परीक्षण के व्यवस्थित चरण को कम करें।

public class TestConventionsAttribute : AutoDataAttribute 
{ 
    public TestConventionsAttribute() 
     : base(new Fixture().Customize(new AutoMoqCustomization())) 
    { 
    } 
} 

HTH


नमूना प्रकार में प्रयोग किया:

[Theory, TestConventions] 
public void ShouldGetItemWithSameId(
    [Frozen]Mock<IDataFacade> facadeStub, 
    BusinessLogic sut, 
    int expected) 
{ 
    facadeStub 
     .Setup(c => c.Get(It.IsAny<int>())) 
     .Returns((int i) => new Item { Key = i }); 

    var result = sut.Get(expected); 
    var actual = result.Key; 

    Assert.Equal(expected, actual); 
} 

TestConventions विशेषता के रूप में परिभाषित किया गया है: यहाँ मूल परीक्षण AutoFixture.Xunit की खुद की इकाई परीक्षण डीएसएल का उपयोग कर फिर से लिखा है उदाहरण:

public class Item 
{ 
    public int Key { get; set; } 
} 

public interface IDataFacade 
{ 
    Item Get(int p); 
} 

public class BusinessLogic 
{ 
    private readonly IDataFacade facade; 

    public BusinessLogic(IDataFacade facade) 
    { 
     this.facade = facade; 
    } 

    public Item Get(int p) 
    { 
     return this.facade.Get(p); 
    } 
} 
+1

मुझे यह पसंद है। मैं इसे आजमाउंगा और बाद में टिप्पणी करूंगा। धन्यवाद :) –

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