के बजाय थ्रेडस्टैटिक का उपयोग करने में क्या गड़बड़ है, मैं एक बहुत बड़ी, बहुत विरासत परियोजना टेस्ट करने योग्य बनाने की कोशिश कर रहा हूं।डीआई कंटेनर
हमारे पास कई सांख्यिकीय रूप से उपलब्ध सेवाएं हैं जो हमारे अधिकांश कोड का उपयोग करती हैं। समस्या यह है कि ये नकली करना मुश्किल है। वे सिंगलेट्स थे। अब वे छद्म-सिंगलेट्स हैं - एक ही स्थिर इंटरफ़ेस लेकिन फ़ंक्शन एक इंस्टेंस ऑब्जेक्ट को प्रतिनिधि करते हैं जिन्हें स्विच किया जा सकता है। इस तरह:
class ServiceEveryoneNeeds
{
public static IImplementation _implementation = new RealImplementation();
public IEnumerable<FooBar> GetAllTheThings() { return _implementation.GetAllTheThings(); }
}
अब मेरी इकाई परीक्षण में:
void MyTest()
{
ServiceEveryoneNeeds._implementation = new MockImplementation();
}
अब तक तो अच्छा। प्रोड में, हमें केवल एक कार्यान्वयन की आवश्यकता है। लेकिन परीक्षण समानांतर में चलाने के लिए और अलग अलग mocks आवश्यकता हो सकती है, तो मैं ऐसा किया:
class Dependencies
{
//set this in prod to the real impl
public static IImplementation _realImplementation;
//unit tests set these
[ThreadStatic]
public static IImplementation _mock;
public static IImplementation TheImplementation
{ get {return _realImplementation ?? _mock; } }
public static void Cleanup() { _mock = null; }
}
और फिर:
class ServiceEveryoneNeeds
{
static IImplementation GetImpl() { return Dependencies.TheImplementation; }
public static IEnumerable<FooBar> GetAllTheThings() {return GetImpl().GetAllTheThings(); }
}
//and
void MyTest()
{
Dependencies._mock = new BestMockEver();
//test
Dependencies.Cleanup();
}
हम इस मार्ग है क्योंकि यह निर्माता के लिए हर वर्ग में इन सेवाओं इंजेक्षन एक बड़े पैमाने पर परियोजना है ले लिया उन्हें उनकी जरूरत है। साथ ही, ये हमारे कोडबेस के भीतर सार्वभौमिक सेवाएं हैं जिन पर अधिकांश कार्य निर्भर करते हैं।
मैं समझता हूं कि यह पैटर्न इस अर्थ में बुरा है कि यह निर्भरता को छुपाता है, क्योंकि कन्स्ट्रक्टर इंजेक्शन के विपरीत निर्भरता स्पष्ट करता है।
हालांकि लाभ हैं:
- हम तुरंत यूनिट परीक्षण शुरू कर सकते हैं, 3 महीने के रिएक्टर और फिर यूनिट परीक्षण कर सकते हैं।
- हमारे पास अभी भी ग्लोबल्स हैं, लेकिन यह हम कहां से सख्ती से बेहतर प्रतीत होते हैं।
जबकि हमारी निर्भरता अभी भी निहित है, मैं तर्क दूंगा कि यह दृष्टिकोण हमारे पास जो भी था उससे सख्ती से बेहतर है। छिपी निर्भरताओं के अलावा, क्या यह उचित डी कंटेनर का उपयोग करने से किसी भी तरह से खराब है? मैं किस समस्या में भागूँगा?
नहीं, यह एक सेवा लोकेटर नहीं है। यह एक परिवेश संदर्भ है। मामूली लेकिन महत्वपूर्ण अंतर यह है कि प्रकार अच्छी तरह से परिभाषित किया गया है जहां एक सेवा लोकेटर को किसी भी प्रकार के प्रदान करने के लिए डिज़ाइन किया गया है।और एक स्थानीय डिफ़ॉल्ट है इसलिए कोड डिफ़ॉल्ट व्यवहार के साथ किसी कॉन्फ़िगरेशन के बिना चलाएगा, लेकिन यह अभी भी एक अलग व्यवहार प्राप्त करने के लिए स्थानीय डिफ़ॉल्ट को प्रतिस्थापित करने की अनुमति देता है। यदि सही परिस्थितियों में उपयोग किया जाता है तो यह बुरा नहीं है। हालांकि हालात बहुत दुर्लभ हैं। –
हां, तकनीकी रूप से आप बिल्कुल सही हैं। लेकिन व्यक्तिगत रूप से मैं एक परिवेश संदर्भ के रूप में एक पूर्ण उड़ा सेवा का उल्लेख नहीं करता। 'टाइमप्रोवाइडर' के मार्क सेमैन के नमूने में एक छोटा और अच्छी तरह से परिभाषित गुंजाइश है। 'ServiceEveryOneNeeds' ... ऐसा नहीं लगता है। –