2009-09-17 4 views
5

यूनिट परीक्षण उद्देश्य के लिए मैं DataServiceQuery का नकल कैसे कर सकता हूं?एक DataServiceQuery मॉकिंग <TElement>

लांग विवरण का पालन करें: जहां एक ADO.NET DataService है कि हमारे मॉडल की भंडारण समाहित करने के लिए नियंत्रक वार्ता (उदाहरण के लिए हम ग्राहकों की एक सूची पढ़ने जाएगा) , एक ASP.NET MVC आवेदन की कल्पना करें। सेवा के लिए एक संदर्भ के साथ, हम एक उत्पन्न वर्ग DataServiceContext से इनहेरिट मिलती है:

namespace Sample.Services 
{ 
    public partial class MyDataContext : global::System.Data.Services.Client.DataServiceContext 
    { 
    public MyDataContext(global::System.Uri serviceRoot) : base(serviceRoot) { /* ... */ } 

    public global::System.Data.Services.Client.DataServiceQuery<Customer> Customers 
    { 
     get 
     { 
     if((this._Customers==null)) 
     { 
      this._Customers = base.CreateQuery<Customer>("Customers"); 
     } 
     return this._Customers; 
     } 
    } 
    /* and many more members */ 
    } 
} 

नियंत्रक हो सकता है:

namespace Sample.Controllers 
{ 
    public class CustomerController : Controller 
    { 
    private IMyDataContext context; 

    public CustomerController(IMyDataContext context) 
    { 
     this.context=context; 
    } 

    public ActionResult Index() { return View(context.Customers); } 
    } 
} 

आप देख सकते हैं, मैं एक निर्माता है कि एक IMyDataContext उदाहरण तो स्वीकार करता है इस्तेमाल किया

[TestFixture] 
public class TestCustomerController 
{ 
    [Test] 
    public void Test_Index() 
    { 
    MockContext mockContext = new MockContext(); 
    CustomerController controller = new CustomerController(mockContext); 

    var customersToReturn = new List<Customer> 
    { 
     new Customer{ Id=1, Name="Fred" }, 
     new Customer{ Id=2, Name="Wilma" } 
    }; 
    mockContext.CustomersToReturn = customersToReturn; 

    var result = controller.Index() as ViewResult; 

    var models = result.ViewData.Model; 

    //Now we have to compare the Customers in models with those in customersToReturn, 
    //Maybe by loopping over them? 
    foreach(Customer c in models) //*** LINE A *** 
    { 
     //TODO: compare with the Customer in the same position from customersToreturn 
    } 
    } 
} 

MockContext और MyDataContext एक ही इंटरफ़ेस IMyDataContext लागू करने की आवश्यकता:

हम अपने इकाई परीक्षण में एक नकली उपयोग कर सकते हैं कि
namespace Sample.Services 
{ 
    public interface IMyDataContext 
    { 
    DataServiceQuery<Customer> Customers { get; } 
    /* and more */ 
    } 
} 

हालांकि, जब हम कोशिश करते हैं और MockContext वर्ग को लागू है, हम समस्याओं में DataServiceQuery (जो, स्पष्ट होना, हम IMyDataContext इंटरफ़ेस में प्रयोग कर रहे हैं बस क्योंकि है कि डेटा प्रकार हमने पाया है की प्रकृति के कारण चलाने स्वत: जेनरेट की गई MyDataContext क्लास में हमने शुरुआत की थी)। हम एक DataServiceQuery उदाहरण का दृष्टांत, CustomersToReturn में ग्राहकों से पॉप्युलेट, और यह वापस किए जाने वाले

public class MockContext : IMyDataContext 
{ 
    public IList<Customer> CustomersToReturn { set; private get; } 

    public DataServiceQuery<Customer> Customers { get { /* ??? */ } } 
} 

ग्राहकों में मनुष्य: यदि हम लिखने की कोशिश। जिन समस्याओं में मैं भागता हूं:

1 ~ DataServiceQuery का कोई सार्वजनिक निर्माता नहीं है; एक को तत्काल करने के लिए आपको DataServiceContext पर CreateQuery को कॉल करना चाहिए; MSDN

2 ~ दिखाई देता है तो मैं MockContext रूप में अच्छी तरह DataServiceContext से विरासत, और CreateQuery फोन का उपयोग करने के लिए एक DataServiceQuery, सेवा और क्वेरी प्राप्त करने के लिए एक वैध URI और, जब मैं पुनरावृति करने की कोशिश करने के लिए संबद्ध किया जा सके कर लिया है या क्वेरी में ऑब्जेक्ट्स तक पहुंचें, यह उस यूआरआई के खिलाफ कोशिश करेगा और निष्पादित करेगा। दूसरे शब्दों में, अगर मैं इस तरह के रूप MockContext बदलने के लिए:

namespace Sample.Tests.Controllers.Mocks 
{ 
    public class MockContext : DataServiceContext, IMyDataContext 
    { 
    public MockContext() :base(new Uri("http://www.contoso.com")) { } 

    public IList<Customer> CustomersToReturn { set; private get; } 

    public DataServiceQuery<Customer> Customers 
    { 
     get 
     { 
     var query = CreateQuery<Customer>("Customers"); 
     query.Concat(CustomersToReturn.AsEnumerable<Customer>()); 
     return query; 
     } 
    } 
    } 
} 

फिर, इकाई परीक्षण में, हम लाइन पर एक त्रुटि पंक्ति एक के रूप में चिह्नित है, क्योंकि http://www.contoso.com हमारी सेवा को होस्ट नहीं करता मिलता है। LINE ए मॉडल में तत्वों की संख्या प्राप्त करने का प्रयास करता है, भले ही एक ही त्रुटि ट्रिगर हो। अग्रिम धन्यवाद।

उत्तर

0

[अस्वीकरण - मैं Typemock पर काम]

आप एक मजाक ढांचे का उपयोग कर विचार किया है?

आप DataServiceQuery का एक नकली उदाहरण बनाने के लिए Typemock अलगाने का उपयोग कर सकते हैं:

var fake = Isolate.Fake.Instance<DataServiceQuery>(); 

और आप एक ऐसी ही नकली DataServiceContext बना सकते हैं और यह बजाय इसे वारिस करने की कोशिश कर के व्यवहार है निर्धारित कर सकते हैं।

+0

Dror, विचार के लिए धन्यवाद, लेकिन कुछ समय के लिए हम किसी भी मजाक ढांचे का उपयोग नहीं कर रहे हैं। हमें यह देखने में दिलचस्पी होगी कि कोई ऐसा समाधान है जो एक पर भरोसा नहीं करता है। फिर भी, धन्यवाद – FOR

+0

क्या आपके पास एक मॉकिंग फ्रेमवर्क का उपयोग न करने का एक विशिष्ट कारण है? –

+0

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

4

मैं दो कार्यान्वयन के साथ एक अंतरफलक IDataServiceQuery बनाने के द्वारा इस हल:

  • DataServiceQueryWrapper
  • MockDataServiceQuery

मैं तो IDataServiceQuery का उपयोग जहाँ भी मैं पहले करना होगा एक DataServiceQuery इस्तेमाल किया।

public interface IDataServiceQuery<TElement> : IQueryable<TElement>, IEnumerable<TElement>, IQueryable, IEnumerable 
{ 
    IDataServiceQuery<TElement> Expand(string path); 

    IDataServiceQuery<TElement> IncludeTotalCount(); 

    IDataServiceQuery<TElement> AddQueryOption(string name, object value); 
} 

DataServiceQueryWrapper यह निर्माता में प्रतिनिधियों क्वेरी में पारित करने के लिए सभी कार्यक्षमता एक DataServiceQuery लेता है और उसके बाद। इसी तरह, MockDataServiceQuery एक IQueryable और प्रतिनिधियों सब कुछ क्वेरी के लिए यह कर सकते हैं लगता है।

नकली IDataServiceQuery विधियों के लिए, मैं वर्तमान में केवल this लौटाता हूं, हालांकि आप कार्यक्षमता का नकल करने के लिए कुछ कर सकते हैं यदि आप चाहते हैं।

उदाहरण के लिए:

// (in DataServiceQueryWrapper.cs) 
public IDataServiceQuery<TElement> Expand(string path) 
{ 
    return new DataServiceQueryWrapper<TElement>(_query.Expand(path)); 
} 

 

// (in MockDataServiceQuery.cs) 
public IDataServiceQuery<TElement> Expand(string path) 
{ 
    return this; 
}