2008-12-11 16 views
7

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

प्रस्तुतकर्ता

[TestMethod] 
public void Can_Get_Files() 
{ 
    var view = new FakeFtpView(); 
    var presenter = new FtpPresenter(view, new FakeFtpService(), new FakeFileValidator()); 

    view.GetFiles(); 
    Assert.AreEqual(Messages.Done, view.StatusMessage); 
} 

थ्रेडिंग अब के बाद मैं प्रस्तुतकर्ता के लिए एक SynchronizationContext थ्रेडिंग जोड़ा इससे पहले कि थ्रेडिंग

public class FtpPresenter : IFtpPresenter 
{ 
    ... 
    void _view_GetFilesClicked(object sender, EventArgs e) 
    { 
     _view.StatusMessage = Messages.Loading; 

     try 
     { 
      var settings = new FtpAuthenticationSettings() 
      { 
       Site = _view.FtpSite, 
       Username = _view.FtpUsername, 
       Password = _view.FtpPassword 
      }; 
      var files = _ftpService.GetFiles(settings); 

      _view.FilesDataSource = files; 
      _view.StatusMessage = Messages.Done;   
     } 
     catch (Exception ex) 
     { 
      _view.StatusMessage = ex.Message; 
     } 
    } 
    ... 
} 

टेस्ट इससे पहले कि मैं StatusMessage के लिए मेरे नकली दृश्य पर एक AutoResetEvent स्थापित करने के लिए कोशिश की, लेकिन जब मैं सिंक्रनाइज़ेशन कॉन्टेक्स्ट परीक्षण को चलाता हूं। वर्तमान शून्य है। मुझे एहसास है कि मेरे नए प्रेजेंटर में जो थ्रेडिंग मॉडल मैं उपयोग कर रहा हूं वह सही नहीं है, लेकिन क्या यह मल्टीथ्रेडिंग परीक्षण के लिए सही तकनीक है? मेरा सिंक्रनाइज़ेशन कॉन्टेक्स्ट। कंटेंट नल क्यों है? इसके बजाय मुझे क्या करना चाहिए?

प्रस्तुतकर्ता

[TestMethod] 
public void Can_Get_Files() 
{ 
    var view = new FakeFtpView(); 
    var presenter = new FtpPresenter(view, new FakeFtpService(), new FakeFileValidator()); 

    view.GetFiles(); 
    view.GetFilesWait.WaitOne(); 
    Assert.AreEqual(Messages.Done, view.StatusMessage); 
} 

नकली देखें सूत्रण के बाद

public class FakeFtpView : IFtpView 
{ 
    ... 
    public AutoResetEvent GetFilesWait = new AutoResetEvent(false); 
    public event EventHandler GetFilesClicked = delegate { }; 
    public void GetFiles() 
    { 
     GetFilesClicked(this, EventArgs.Empty); 
    } 
    ... 
    private List<string> _statusHistory = new List<string>(); 
    public List<string> StatusMessageHistory 
    { 
     get { return _statusHistory; } 
    } 
    public string StatusMessage 
    { 
     get 
     { 
      return _statusHistory.LastOrDefault(); 
     } 
     set 
     { 
      _statusHistory.Add(value); 
      if (value != Messages.Loading) 
       GetFilesWait.Set(); 
     } 
    } 
    ... 
} 
+0

अच्छा सवाल! मैं इसी तरह की समस्या को हल करने की कोशिश कर रहा हूं! –

उत्तर

3

कि वह कहाँ है मैं ASP.NET MVC के साथ इसी तरह की समस्याओं आई है HttpContext थ्रेडिंग

public class FtpPresenter : IFtpPresenter 
{ 
    ... 
    void _view_GetFilesClicked(object sender, EventArgs e) 
    { 
     _view.StatusMessage = Messages.Loading; 

     try 
     { 
      var settings = new FtpAuthenticationSettings() 
      { 
       Site = _view.FtpSite, 
       Username = _view.FtpUsername, 
       Password = _view.FtpPassword 
      }; 
      // Wrap the GetFiles in a ThreadStart 
      var syncContext = SynchronizationContext.Current; 
      new Thread(new ThreadStart(delegate 
      { 
       var files = _ftpService.GetFiles(settings); 
       syncContext.Send(delegate 
       { 
        _view.FilesDataSource = files; 
        _view.StatusMessage = Messages.Done; 
       }, null); 
      })).Start(); 
     } 
     catch (Exception ex) 
     { 
      _view.StatusMessage = ex.Message; 
     } 
    } 
    ... 
} 

टेस्ट के बाद वह गायब है एक चीज जो आप कर सकते हैं वह एक वैकल्पिक कन्स्ट्रक्टर प्रदान करता है जो आपको एक नकली सिंक्रनाइज़ेशन कॉन्टेक्स्ट इंजेक्ट करने या एक सार्वजनिक सेटटर का पर्दाफाश करने की अनुमति देता है जो वही काम करता है। यदि आप आंतरिक रूप से सिंक्रनाइज़ेशन कॉन्टेक्स्ट को नहीं बदल सकते हैं, तो एक डिफॉल्ट कन्स्ट्रक्टर में सिंक्रनाइज़ेशन कॉन्टेक्स्ट.क्यूरेंट पर सेट की गई संपत्ति बनाएं और उस कोड का उपयोग अपने पूरे कोड में करें। अपने वैकल्पिक कन्स्ट्रक्टर में, आप संपत्ति के लिए नकली संदर्भ असाइन कर सकते हैं - या यदि आप इसे सार्वजनिक सेटटर देते हैं तो आप इसे सीधे असाइन कर सकते हैं।

सार्वजनिक वर्ग FtpPresenter: IFtpPresenter { सार्वजनिक सिंक्रनाइज़ेशन कॉन्टेक्स्ट CurrentContext {प्राप्त करें; सेट; }

public FtpPresenter() : this(null) { } 

    public FtpPresenter(SynchronizationContext context) 
    { 
     this.CurrentContext = context ?? SynchronizationContext.Current; 
    } 

    void _view_GetFilesClicked(object sender, EventArgs e) 
    { 
    .... 
    new Thread(new ThreadStart(delegate 
     { 
      var files = _ftpService.GetFiles(settings); 
      this.CurrentContext.Send(delegate 
      { 
       _view.FilesDataSource = files; 
       _view.StatusMessage = Messages.Done; 
      }, null); 
     })).Start(); 

    ... 
    } 

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

यदि सिंक्रनाइज़ेशन कॉन्टेक्स्ट.क्यूरेंट मौजूद नहीं है तो कन्स्ट्रक्टर कहलाता है, तो आपको असाइनमेंट लॉजिक को गेटटर में चालू करने और आलसी लोड करने की आवश्यकता हो सकती है।

+0

सिंक्रनाइज़ेशन कॉन्टेक्स्ट.क्यूरेंट की जगह में मेरे परीक्षण में मैं क्या उपयोग करूं? क्या आपके पास कोई कोड नमूने हैं? – bendewey

+0

मुझे नहीं पता कि सिंक्रनाइज़ेशन कॉन्टेक्स्ट एक इंटरफ़ेस के अनुरूप है या नहीं। यदि ऐसा है, तो आप एक कक्षा का नकल कर सकते हैं जो एक ही इंटरफ़ेस का उपयोग करता है और इसके बजाय इंटरफ़ेस इंजेक्ट करता है। यदि नहीं, तो आप सिंक्रनाइज़ेशन कॉन्टेक्स्ट के चारों ओर एक रैपर को परिभाषित कर सकते हैं जो कार्यान्वित (अपना स्वयं का) इंटरफ़ेस लागू करता है और रैपर वर्ग का नकल करता है। – tvanfosson

+0

एमवीसी स्रोत पेड़ में www.codeplex.com/aspnet पर HttpContextWrapper (जो मैं परिचित हूं) के स्रोत को देखें, यह कैसे करें इसे कैसे करें। – tvanfosson

1

आपको अपने प्रस्तुतकर्ता में बहुत अधिक ऐप-लॉजिक होना है। मैं एक ठोस मॉडल के अंदर संदर्भ और धागे छुपाता हूं और अकेले कार्यक्षमता का परीक्षण करता हूं।

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