moq

2012-02-28 11 views
87

मैं कोड के इस बिंदु पर अटक कर रहा हूँ के साथ ConfigurationManager.AppSettings है कि मैं कैसे उपहास करने के लिए पता नहीं है नकली कैसे करें:moq

ConfigurationManager.AppSettings["User"]; 

मैं ConfigurationManager उपहास करने के लिए है, लेकिन मैं एक सुराग नहीं है , मैं Moq का उपयोग कर रहा हूं।

कोई मुझे एक टिप दे सकता है? धन्यवाद!

उत्तर

84

मेरा मानना ​​है कि इसका एक मानक दृष्टिकोण मुखौटा पैटर्न कॉन्फ़िगरेशन मैनेजर को लपेटने के लिए उपयोग करना है और फिर आपके पास कुछ कम है जो आपके पास नियंत्रण है।

तो आप कॉन्फ़िगरेशन प्रबंधक को लपेटेंगे। कुछ की तरह:

public class Configuration: IConfiguration 
{ 
    public User 
    { 
     get{ 
       return ConfigurationManager.AppSettings["User"]; 
     } 
    } 
} 

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

+6

यह अवधारणात्मक रूप से मैं भी कर रहा हूं। हालांकि, मैं कैसल डिक्शनरी एडाप्टर ([कैसल] का हिस्सा (http://www.castleproject.org) कोर) का उपयोग करता हूं जो फ्लाई पर इंटरफ़ेस के कार्यान्वयन को उत्पन्न करता है। मैंने इसके बारे में कुछ समय पहले लिखा है: http://blog.andreloker.de/post/2008/09/05/Getting-rid-of-strings-(3)-take-your-app-settings-to- अगली-लेवल.एएसपीएक्स (कैसल डिक्शनरी एडाप्टर का उपयोग करने के तरीके को देखने के लिए "एक समाधान" तक स्क्रॉल करें) –

+0

यह निफ्टी है और यह एक अच्छा लेख है। मुझे भविष्य के लिए इसे ध्यान में रखना होगा। –

+0

मैं आपके शुद्धता और व्याख्याओं के आधार पर भी जोड़ सकता हूं - इसके बजाय इसे एक प्रतिनिधि प्रॉक्सी या एडाप्टर भी कहा जा सकता है। –

16

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

+7

देखें यदि परीक्षण के तहत कोड का व्यवहार कॉन्फ़िगरेशन मान के मान के आधार पर बदलता है, तो यह निश्चित रूप से आसान है इसका परीक्षण करने के लिए यदि यह सीधे AppSettings पर निर्भर नहीं है। –

+0

यह खराब अभ्यास है क्योंकि आप कभी भी अन्य संभावित सेटिंग्स का परीक्षण नहीं कर रहे हैं। जोशुआ एनफील्ड का जवाब परीक्षण के लिए बहुत अच्छा है। – mkaj

+3

जबकि अन्य इस उत्तर के खिलाफ हैं, मैं कहूंगा कि उनकी स्थिति थोड़ा सामान्यीकृत है। यह कुछ परिदृश्यों में एक बहुत ही वैध उत्तर है और यह वास्तव में केवल आपकी आवश्यकताओं के आधार पर निर्भर करता है। उदाहरण के लिए, मान लें कि मेरे पास 4 अलग-अलग क्लस्टर हैं, जिनमें से प्रत्येक का एक अलग बेस यूआरएल है। प्रोजेक्ट को शामिल करने वाले 'Web.config' से, उन 4 क्लस्टर को रनटाइम के दौरान खींच लिया जाता है। परीक्षण के दौरान, 'app.config' से कुछ प्रसिद्ध मान खींचना बहुत मान्य है। इकाई परीक्षण को केवल यह सुनिश्चित करने की आवश्यकता है कि जब यह "क्लस्टर 1" काम करता है तो स्थितियां; इस मामले में केवल 4 अलग-अलग क्लस्टर हैं। –

2

यह एक स्थिर संपत्ति है, और मोक को एमओसी इंस्टेंस विधियों या कक्षाओं के लिए डिज़ाइन किया गया है जिन्हें विरासत के माध्यम से मजाक किया जा सकता है। दूसरे शब्दों में, मोक आपको यहां कोई मदद नहीं करेगा।

सांख्यिकी का मज़ाक उड़ाते हुए, मैं Moles नामक एक उपकरण का उपयोग करता हूं, जो मुफ़्त है। अन्य ढांचे अलगाव उपकरण हैं, जैसे कि टाइपपेक जो यह भी कर सकते हैं, हालांकि मुझे लगता है कि वे भुगतान उपकरण हैं।

जब यह सांख्यिकी और परीक्षण की बात आती है, तो दूसरा विकल्प स्थिर स्थिति स्वयं बनाना है, हालांकि यह अक्सर समस्याग्रस्त हो सकता है (जैसा कि, मुझे लगता है कि यह आपके मामले में होगा)।

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

13

आप कस्टम NameValueCollection ऑब्जेक्ट में AppSettings को संशोधित करने के लिए शिम्स का उपयोग कर सकते हैं।

[TestMethod] 
public void TestSomething() 
{ 
    using(ShimsContext.Create()) { 
     const string key = "key"; 
     const string value = "value"; 
     ShimConfigurationManager.AppSettingsGet =() => 
     { 
      NameValueCollection nameValueCollection = new NameValueCollection(); 
      nameValueCollection.Add(key, value); 
      return nameValueCollection; 
     }; 

     /// 
     // Test code here. 
     /// 

     // Validation code goes here.   
    } 
} 

आप Isolating Code Under Test with Microsoft Fakes, पर की परतें और नकली के बारे में अधिक पढ़ सकते हैं: आप इसे इस तरह प्राप्त कर सकते हैं का एक उदाहरण है। उम्मीद है की यह मदद करेगा।

+5

लेखक एमएसएक्स के बारे में नहीं पूछ रहा है, एमएस फॉक्स के बारे में नहीं। – JPCF

+6

और यह कैसे अलग है? यह डेटा कोड निर्भरता को अपने कोड से हटाकर मजाक कर रहा है। सी # नकल का उपयोग एक दृष्टिकोण है! – Zorayr

87

मैं AspnetMvc4 का उपयोग कर रहा हूं। एक पल पहले मैंने

ConfigurationManager.AppSettings["mykey"] = "myvalue"; 

मेरी टेस्ट विधि में लिखा और यह पूरी तरह से काम किया।

स्पष्टीकरण: परीक्षण विधि एप सेटिंग्स के साथ संदर्भ में चलती है, आमतौर पर web.config या myapp.configConfigurationsManager इस एप्लिकेशन-वैश्विक वस्तु तक पहुंच सकता है और इसे कुशल बना सकता है।

हालांकि: यदि आपके पास समानांतर में परीक्षण धावक परीक्षण चल रहा है तो यह एक अच्छा विचार नहीं है।

+3

यह समस्या हल करने के लिए वास्तव में चालाक और सरल तरीका है!सादगी के लिए कुडोस! – Navap

+1

ज्यादातर मामलों में एक अमूर्तता बनाने से कहीं अधिक आसान –

+0

यह है ???? प्रतिभा सादगी में है क्योंकि मैं इस मस्तिष्क को इस विशेष मोहरबंद वर्ग का परीक्षण करने के तरीके पर रैक कर रहा था। – ppumkin

7

क्या आपने मॉकिंग के बजाय स्टबिंग माना है? AppSettings संपत्ति एक NameValueCollection है:

[TestClass] 
public class UnitTest1 
{ 
    [TestMethod] 
    public void TestMethod1() 
    { 
     // Arrange 
     var settings = new NameValueCollection {{"User", "Otuyh"}}; 
     var classUnderTest = new ClassUnderTest(settings); 

     // Act 
     classUnderTest.MethodUnderTest(); 

     // Assert something... 
    } 
} 

public class ClassUnderTest 
{ 
    private readonly NameValueCollection _settings; 

    public ClassUnderTest(NameValueCollection settings) 
    { 
     _settings = settings; 
    } 

    public void MethodUnderTest() 
    { 
     // get the User from Settings 
     string user = _settings["User"]; 

     // log 
     Trace.TraceInformation("User = \"{0}\"", user); 

     // do something else... 
    } 
} 

लाभ एक सरल कार्यान्वयन और System.Configuration पर कोई निर्भरता जब तक आप वास्तव में इसकी जरूरत है।

+0

मुझे यह दृष्टिकोण सबसे अच्छा लगता है। एक तरफ, कॉन्फ़िगरेशन मैनेजर को 'आईकोनफिगरेशन' के साथ लपेटना क्योंकि यहोशू एनफील्ड का सुझाव बहुत अधिक स्तर हो सकता है, और आप खराब कॉन्फ़िगरेशन मूल्य पार्सिंग जैसी चीजों के कारण मौजूद बग को याद कर सकते हैं। दूसरी तरफ, 'ConfigurationManager.AppSettings' का उपयोग सीधे लॉसमैनोस के सुझाव के रूप में एक कार्यान्वयन विस्तार का बहुत अधिक है, इसका उल्लेख नहीं है कि इसका अन्य परीक्षणों पर साइड इफेक्ट्स हो सकते हैं और मैन्युअल सिंक्रनाइज़ेशन के बिना समांतर परीक्षण रनों में उपयोग नहीं किया जा सकता है (' NameValueConnection' धागा सुरक्षित नहीं है)। –

1

मुझे लगता है कि आप लिख रहे हैं app.config प्रदाता एक साधारण काम है और फिर कुछ और उपयोगी है। विशेष रूप से आपको शिम आदि जैसे किसी भी झगड़े से बचना चाहिए क्योंकि जैसे ही आप उनका उपयोग करते हैं & संपादित करें अब काम नहीं करता है।

प्रदाताओं मैं इस तरह नजर का उपयोग करें:

डिफ़ॉल्ट रूप से वे App.config से मूल्यों को प्राप्त लेकिन इकाई परीक्षण के लिए मैं सभी मूल्यों को भी पार और स्वतंत्र रूप से प्रत्येक परीक्षा में उन्हें इस्तेमाल कर सकते हैं।

किसी भी इंटरफेस की आवश्यकता नहीं है या बार-बार इसे लागू करने की आवश्यकता नहीं है। मेरे पास एक यूटिलिटीज डीएल है और कई परियोजनाओं और यूनिट परीक्षणों में इस छोटे से सहायक का उपयोग करें।

public class AppConfigProvider 
{ 
    public AppConfigProvider() 
    { 
     ConnectionStrings = new ConnectionStringsProvider(); 
     AppSettings = new AppSettingsProvider(); 
    } 

    public ConnectionStringsProvider ConnectionStrings { get; private set; } 

    public AppSettingsProvider AppSettings { get; private set; } 
} 

public class ConnectionStringsProvider 
{ 
    private readonly Dictionary<string, string> _customValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); 

    public string this[string key] 
    { 
     get 
     { 
      string customValue; 
      if (_customValues.TryGetValue(key, out customValue)) 
      { 
       return customValue; 
      } 

      var connectionStringSettings = ConfigurationManager.ConnectionStrings[key]; 
      return connectionStringSettings == null ? null : connectionStringSettings.ConnectionString; 
     } 
    } 

    public Dictionary<string, string> CustomValues { get { return _customValues; } } 
} 

public class AppSettingsProvider 
{ 
    private readonly Dictionary<string, string> _customValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); 

    public string this[string key] 
    { 
     get 
     { 
      string customValue; 
      return _customValues.TryGetValue(key, out customValue) ? customValue : ConfigurationManager.AppSettings[key]; 
     } 
    } 

    public Dictionary<string, string> CustomValues { get { return _customValues; } } 
}