2013-08-10 11 views
34

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

तो चलो मेरे प्रश्न से शुरू करते हैं।

AutoFixture/AutoMoq ignores injected instance/frozen mock

ऊपर के लिंक का दिलचस्प हिस्सा के अनुसार इस कोड

Mock<ISettings> settingsMock = new Mock<ISettings>(); 
settingsMock.Setup(s => s.Get(settingKey)).Returns(xmlString); 

ISettings settings = settingsMock.Object; 
fixture.Inject(settings); 

जो मार्क उत्तर देने के लिए यह

fixture.Freeze<Mock<ISettings>>() 
     .Setup(s => s.Get(settingKey)).Returns(xmlString); 

यह एक तरह लग रहा है फिर से लिखा जा सकता है दिया जाता है फ्रीज विधि का उपयोग करते हुए सिंटैक्सिक चीनी, झुकाव इंटरफ़ेस में नकली, कॉन्फ़िगरेशन और इंजेक्शन के निर्माण में लिखने का एक तरीका है ऑटोफिक्चर कंटेनर में।

वेब पर कुछ शोध करने के बाद, वास्तव में फ्रीज और इंजेक्ट के बीच एक कार्यात्मक अंतर होता है। मैं इस सवाल पाया: https://github.com/AutoFixture/AutoFixture/issues/59 जो How can I Freeze a null instance in AutoFixture

लिंक के लेखक का जवाब बात ऊपर निम्नलिखित के रूप में फ्रीज विधि का वर्णन:

आंतरिक रूप से, फ्रीज का अनुरोध प्रकार का एक उदाहरण बनाता है (उदाहरण के लिए IPayPalConfiguration) और फिर उसे इंजेक्शन तो वह हमेशा वापस आ जाएगी कि उदाहरण है जब आप इसे फिर से

मैं अंडर का अनुरोध टंड कि जब हम

var customer = fixture.Freeze<Order>(); 

जब भी हमारे कोड ऑर्डर प्रकार का अनुरोध करते हैं तो यह हमेशा आदेश के उसी उदाहरण का उपयोग करेगा। लेकिन अगर मैं फ्रीज कन्स्ट्रक्टर में निर्दिष्ट करता हूं तो मैं इसे एक विशिष्ट उदाहरण का उपयोग करना चाहता हूं?

[Fact] 
public void MethodeName() 
{ 
    var fixture = new Fixture().Customize(new AutoMoqCustomization()); 
    fixture.Freeze<OrderLine>(new OrderLine("Foo")); 
    var order = fixture.Create<Order>(); 
} 

public class Order 
{ 
    private readonly OrderLine _line; 

    public Order(OrderLine line) 
    { 
     _line = line; 
    } 
} 
public class OrderLine 
{ 
    private readonly string _name; 

    public OrderLine(string name) 
    { 
     _name = name; 
    } 
} 

ऑर्डर लाइन के नाम पर बराबर करने के लिए "फू" namefe48163a-d5a0-49a5-b349-7b11ba5f804b के बजाय नहीं होना चाहिए:

यह एक छोटा सा कोड उदाहरण है? फ्रीज विधि का दस्तावेज कहता है:

<typeparam name="T">The type to freeze.</typeparam> 
<param name="fixture">The fixture.</param> 
<param name="seed">Any data that adds additional information when creating the anonymous object. Hypothetically, this value might be the value being frozen, but this is not likely.</param> 

लेखक को यह सुनिश्चित नहीं है कि मूल्य कब वापस किया जाता है? अगर मैं निर्दिष्ट करता हूं, फ्रीज के निर्माता में मेरा उदाहरण, मैं इस उदाहरण का उपयोग करने के लिए ऑटोफिक्चर की उम्मीद कर रहा हूं?

तो

कृपया ध्यान दें, जमे हुए मूल्य के रूप में प्रयोग की जाने वाली जब तक आप ऐसा करने के लिए अनुकूलित किया गया है संभावना नहीं है। यदि आप स्थिरता में एक विशिष्ट मान इंजेक्ट करना चाहते हैं, तो आपको इसके बजाय विधि का उपयोग करना चाहिए।

ऐसा लगता है कि मुझे बीज पैरामीटर को कस्टमाइज़ करना है। क्या कोई स्पष्टीकरण दे सकता है? प्रलेखन द्वारा इंगित समाधान इंजेक्ट विधि का उपयोग करना है। और वास्तव में, यह ऑर्डरलाइन के साथ मेरे कोड उदाहरण में काम करता है।

मैं फ्रीज, सुई के बीच अंतर को समझते हैं, और यह भी रजिस्टर जो, स्रोत कोड के अनुसार, बस इंजेक्षन विधि द्वारा कहा जाता है करने के लिए आपकी मदद के लिए देख रहा हूँ, लेकिन यह एक लैम्ब्डा लेता है।

उत्तर

34

रजिस्टर और एक समय पर

एक बार सम्मिलित करें, वहाँ कोई Inject और कोई Freeze था ; Register कोड पर शासन किया।

public static void Register<T>(this IFixture fixture, Func<T> creator) 

AutoFixture के निर्माता ने सोचा कि यह था:

public static void Register<T>(this IFixture fixture, T item) 

हालांकि यह इस करीबी रिश्तेदार के साथ एपीआई साझा करने के लिए किया था,:

उस समय वहाँ एक Register अधिभार thusly परिभाषित किया गया था अच्छा, लेकिन हां: उपयोगकर्ताओं को भ्रम के साथ परेशान थे।सबसे गंभीर रूप से, एक उपयोगकर्ता लिख ​​सकते हैं:

fixture.Register(() => universe.LightUp()); 

लेकिन यह भी

fixture.Register(universe.LightUp); 

जो सटीक एक ही बात का मतलब है, क्योंकि universe.LightUp एक विधि के लिए एक संदर्भ है, और इस तरह एक प्रतिनिधि मेल खाता है।

हालांकि, यह वाक्यविन्यास एक संपत्ति संदर्भ की तरह दिखता है, इसलिए यदि LightUp किसी विधि के बजाय एक संपत्ति थी, तो पहले अधिभार को संकलक द्वारा चुना जाएगा।

इससे बहुत भ्रम पैदा हुआ, इसलिए Register<T>(this IFixture fixture, T item) अधिभार का नाम बदलकर Inject<T>(this IFixture fixture, T item) कर दिया गया।

फ्रीज

फ्रीज एक अलग इतिहास है। एक लंबे समय पहले, जब मैं अभी भी एक अनिवार्य तरह से AutoFixture इस्तेमाल किया, मैंने देखा है कि मैं बार-बार इस तरह कोड लिखा है:

var foo = fixture.Create<Foo>(); 
fixture.Inject(foo); 

तो मैंने तय कर लिया है कि यह एक अवधारणा थी और यह फ्रीज नाम दिया है। Freeze विधि कोड की उन दो पंक्तियों के लिए केवल लघुरूप है।

मैं फ्रीज, सुई के बीच अंतर को समझते हैं, और यह भी रजिस्टर जो, स्रोत कोड के अनुसार, बस इंजेक्षन विधि द्वारा कहा जाता है करने के लिए आपकी मदद के लिए देख रहा हूँ, लेकिन यह एक लैम्ब्डा लेता

आम तौर पर, Inject और Register के बीच अंतर करना मुश्किल नहीं होना चाहिए, क्योंकि उनके हस्ताक्षर टकरा नहीं जाते हैं। इस प्रकार, यदि आप उन दो तरीकों में से एक के साथ एक लक्ष्य पूरा करने का प्रयास करते हैं, और आपका कोड संकलित करता है, तो आपने शायद सही संस्करण चुना है।

यह भी Freeze के लिए मामला हो सकता है अगर यह ओपी में इस्तेमाल अधिभार के लिए नहीं था:

[EditorBrowsable(EditorBrowsableState.Never)] 
public static T Freeze<T>(this IFixture fixture, T seed) 

सूचना है कि इस अधिभार वास्तव में EditorBrowsableState.Never है, क्योंकि यह हमेशा लोगों को confuses। हालांकि, इसके बावजूद, स्पष्ट रूप से लोग अभी भी उस अधिभार को पाते हैं, इसलिए मुझे लगता है कि it should be moved in AutoFixture 4। यह उन सुविधाओं है कि मौजूद हैं, क्योंकि इसे लागू करने के लिए आसान था में से एक है ...

+6

बीटीडब्ल्यू। एक कारण यह है कि यह अधिभार अभी भी पाया जा रहा है यह तथ्य हो सकता है कि ReSharper डिफ़ॉल्ट रूप से 'EditorBrowsable' विशेषता को अनदेखा करने के लिए सेट किया गया प्रतीत होता है। ऑटोफिक्चर में – TeaDrivenDev

+1

एफडब्ल्यूआईडब्ल्यू, मैं बीज अधिभार को दूर ले जाने (या दूर ले जाने की योजना बना रहा हूं: https://github.com/AutoFixture/AutoFixture/issues/151 –

13

Freeze, Inject, और Register सभी सृजन एल्गोरिदम अनुकूलित कर रहे हैं।

Inject और Register के साथ आप new OrderLine("Foo") मैन्युअल की आपूर्ति करके स्पष्ट रूप निर्दिष्ट करते हैं है कि एक वस्तु एक खास तरह से बनाया जाना चाहिए, अपने उदाहरण में।

Freeze के साथ आप निर्दिष्ट नहीं कर रहे हैं एक ऑब्जेक्ट बनाया जाना चाहिए - आप ऑटोफिक्चर से आपके लिए एक उदाहरण प्रदान करने के लिए कहते हैं।

fixture.Customize<T>(c => c.FromFactory(creator).OmitAutoProperties());


कारण है कि fixture.Freeze<OrderLine>(new OrderLine("Foo")); निर्दिष्ट बीज मूल्य के साथ एक OrderLine उदाहरण पैदा नहीं करता क्योंकि by default the seed is ignored है:

अंत में, सब से ऊपर तरीकों ही निचले स्तर एपीआई का उपयोग ।

एक विशेष प्रकार का बीज मूल्यों के पक्ष में करने के लिए, आप बना सकते हैं एक SeedFavoringRelay<T>:

public class SeedFavoringRelay<T> : ISpecimenBuilder where T : class 
{ 
    public object Create(object request, ISpecimenContext context) 
    { 
     if (context == null) 
      throw new ArgumentNullException("context"); 

     var seededRequest = request as SeededRequest; 
     if (seededRequest == null || !seededRequest.Request.Equals(typeof(T))) 
      return new NoSpecimen(request); 

     var seed = seededRequest.Seed as T; 
     if (seed == null) 
      return new NoSpecimen(request); 

     return seed; 
    } 
} 

तो फिर तुम यह नीचे के रूप में उपयोग कर सकते हैं:

fixture.Customizations.Add(
    new SeedFavoringRelay<OrderLine>()); 

fixture.Freeze<OrderLine>(new OrderLine("Foo")); 
// -> Now fixture.Create<Order>() creates an Order with OrderLine's Name = "Foo". 
+0

1 - ठीक तो क्यों निम्नलिखित कोड: नकली settingsMock = नई नकली (); सेटिंग्सMock.Setup (एस => एस। गेट (सेटिंगकी))। रिटर्न (xmlString); स्थिरता। इंजेक्ट (सेटिंग्समैक.ऑब्जेक्ट); फ़िक्स्चर के समान है। फ़्रीज़ <मॉक >()। सेटअप (एस => एस। गेट (सेटिंगकी))। रिटर्न (xmlString); आपकी व्याख्या के मुताबिक, मैं सिर्फ मॉक बनाने के लिए ऑटोफिक्चर कह रहा हूं जब किसी को आईसेटिंग का उदाहरण चाहिए, लेकिन सेटअप भाग और रिटर्न भाग फ्रीज भाग के बाहर है। तो यह कैसे जमे हुए है? – Gui

+0

3 - मुझे इंजेक्ट और रजिस्टर का उपयोग कब करना चाहिए? यदि ऑटोफिक्चर इन दो सार्वजनिक तरीकों का प्रस्ताव करता है, तो मुझे लगता है कि ऐसी परिस्थितियां होनी चाहिए जहां कोई दूसरे की तुलना में बेहतर काम करता हो। – Gui

+0

जैसा कि मैंने [इन ऑटोफिक्चर-संबंधी ब्लॉग प्रविष्टियों] में पढ़ा है [http://blog.ploeh.dk/tags।एचटीएमएल # ऑटोफिक्शन-रेफरी), 'फ्रीज' विधि टी के समान उदाहरण देता है जब भी/जहां भी आपके 'स्थिरता' के विशेष उदाहरण को किसी ऑब्जेक्ट को बनाने की आवश्यकता होती है। ये लेख मेरे लिए एक महान संसाधन रहे हैं। – Jeff

1

मैं अपने परीक्षण (जो नहीं करता है 'संशोधित टी वर्तमान में कुछ भी कहें, बीटीडब्लू) और यदि आप इसके निष्पादन के माध्यम से कदम उठाते हैं, तो आपको "फू" के साथ OrderLine दिखाई देगा क्योंकि इसका निजी _लाइन सदस्य मान Order में इंजेक्शन दिया गया है।

मैं परीक्षण है जहाँ मैं OrderLine में Order और Name में OrderLine के लिए केवल पढ़ने के लिए गुण जोड़ा ताकि आप इन वस्तुओं के बारे में दावे कर सकता का एक और संस्करण था, लेकिन है कि न तो यहाँ और न ही नहीं है।

यह परीक्षण स्थिरता FromFactory विधि सीधे का उपयोग कर, उस स्थिति में उपयोगी हो सकता है कभी कभी सेट:

[Fact] 
public void MethodName() 
{ 
    var fixture = new Fixture().Customize(new AutoMoqCustomization()); 
    const string expected = "Foo"; 
    fixture.Customize<OrderLine>(o => o 
     .FromFactory(() => 
      new OrderLine(expected))); 
    var order = fixture.Create<Order>(); 
}