2012-03-30 4 views
8

सामान्य समाधान इसे इंटरफ़ेस के पीछे छिपाना है।यूनिट परीक्षणों में डेटटाइम.अब कैसे नकल करें?

public class RecordService 
{ 
    private readonly ISystemTime systemTime; 

    public RecordService(ISystemTime systemTime) 
    { 
     this.systemTime = systemTime; 
    } 

    public void RouteRecord(Record record) 
    { 
     if (record.Created < 
      systemTime.CurrentTime().AddMonths(-2)) 
     { 
      // process old record 
     } 

     // process the record 
    } 
} 

इकाई परीक्षण में आप नकली वस्तु का उपयोग करें और क्या

[TestClass] 
public class When_old_record_is_processed 
{ 
    [TestMethod] 
    public void Then_it_is_moved_into_old_records_folder() 
    { 
     var systemTime = A.Fake<ISystemTime>(); 
     A.CallTo(() => system.Time.CurrentTime()) 
      .Returns(DateTime.Now.AddYears(-1)); 

     var record = new Record(DateTime.Now); 
     var service = new RecordService(systemTime); 

     service.RouteRecord(record); 

     // Asserts... 
    } 
} 

मैं अपने वर्ग में एक और इंटरफ़ेस इंजेक्षन करने के लिए सिर्फ वर्तमान समय प्राप्त करने के लिए पसंद नहीं है वापस जाने के लिए तय कर सकते हैं। यह इतनी छोटी समस्या के लिए बहुत भारी समाधान महसूस करता है। समाधान सार्वजनिक कार्य के साथ स्थिर वर्ग का उपयोग करना है।

public static class SystemTime 
{ 
    public static Func<DateTime> Now =() => DateTime.Now; 
} 

अब हम ISystemTime इंजेक्शन को हटा सकते हैं और RecordService इस

public class RecordService 
{ 
    public void RouteRecord(Record record) 
    { 
     if (record.Created < SystemTime.Now.AddMonths(-2)) 
     { 
      // process old record 
     } 

    // process the record 
    } 
} 

इकाई परीक्षण हम बस के रूप में आसानी से सिस्टम का समय नकली सकते हैं की तरह लग रहा है।

[TestClass] 
public class When_old_record_is_processed 
{ 
    [TestMethod] 
    public void Then_it_is_moved_into_old_records_folder() 
    { 
     SystemTime.Now =() => DateTime.Now.AddYears(-1); 
     var record = new Record(DateTime.Now); 
     var service = new RecordService(); 

     service.RouteRecord(record); 

     // Asserts... 
    } 
} 

बेशक यह सब कुछ नकारात्मक है। आप सार्वजनिक क्षेत्रों (हॉरर!) का उपयोग कर रहे हैं, इसलिए कोई भी आपको इस तरह कोड लिखने से रोक नहीं रहा है।

public class RecordService 
{ 
    public void RouteRecord(Record record) 
    { 
     SystemTime.Now =() => DateTime.Now.AddYears(10); 
    } 
} 

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

public static class FileSystem 
{ 
    public static Action<string, string> MoveFile = File.Move; 
} 

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

+1

क्या आपने moq का उपयोग किया है? (या कोई अन्य मॉकिंग फ्रेमवर्क) http://code.google.com/p/moq/ – Magrangs

+0

मैंने आपके कोड को बनाने का निर्धारण किया है। इसे सही ढंग से कैसे करें इसे सीखने के लिए कृपया अपने संस्करण में इसकी तुलना करें। –

+1

@ मैग्रांग्स: अन्य सभी "सामान्य" मॉकिंग फ्रेमवर्क के रूप में, मक 'दिनांक समय' जैसी स्थिर विधियों और गुणों का नकल नहीं कर सकता है। –

उत्तर

3

आपको इसे हाथ से लागू करने की आवश्यकता नहीं है। ऐसा करने के लिए आप मोल्स ढांचे का उपयोग कर सकते हैं। channel 9

+2

और moq .. और कई अन्य मॉकिंग फ्रेमवर्क :-) – Magrangs

+0

असल में इस सवाल ने मुझे आश्चर्यचकित कर दिया क्योंकि वीडियो में मॉल का पहला उदाहरण डेटटाइम का मज़ाक करना कितना आसान है.अब :) – daryal

+1

@ मैग्रांग्स: सही नहीं है। उपर्युक्त आपकी अन्य टिप्पणी का मेरा उत्तर देखें। –

3

मैं नहीं कहूंगा कि वर्तमान समय इतना छोटा काम था, यदि आपका आवेदन अंतरराष्ट्रीय हो जाता है और कई समय क्षेत्र में इसका उपयोग किया जाता है, तो आप किस समय का वर्तमान समय प्राप्त कर रहे हैं, संभवतः आप एक चाहते हैं उपयोग करने के लिए आम टाइमज़ोन, कोई फर्क नहीं पड़ता कि आपका लोकेल?

इंटरफ़ेस आपको इस ज्ञान को दूर करने की अनुमति देता है; मैं "वर्तमान" समय को एक जटिल कार्य के रूप में पुनः प्राप्त करने पर विचार करता हूं।

0

ध्यान में रखते हुए कि हम idiomatic C# के बारे में बात कर रहे हैं, मैं इंटरफेस के पीछे समारोह के साथ समस्याओं को समझ में नहीं आता। संक्षेप में, आपके पास TimeProvider है कि आप एक निर्भरता के रूप में निर्माता में इंजेक्ट करते हैं और आप परीक्षण के तहत प्रासंगिक कोड के तर्क को चलाने के लिए इसके लिए एक स्टब प्रदान करते हैं।

मुझे विश्वास नहीं है कि आपके अन्य दृष्टिकोण लाभ प्रदान करते हैं और उनके पास मूर्खतापूर्ण नहीं होने के साथ-साथ निर्भरता इंजेक्शन के उपयोगी पहलुओं को दूर करने का नकारात्मक पहलू है (निर्भरता दस्तावेज, मजाक करना, नियंत्रण में उलझन, इत्यादि ...)