سؤال

أنا فقط التعلم نموذج / عرض / ViewModel نمط انها الاختلافات (عثر / عرض / ViewModel ، أو الموديل / عرض / مقدم).

ما يحيرني هو:إذا كنت تستخدم هذا النمط مع خدمة WCF, هو الخدمة نموذج (عثر), أو هل أنا بحاجة إلى نموذج منفصل لتغليف خدمة WCF طبقة??

عند استخدام رأس المال العامل كما عثر بلدي ViewModel ليست قابلة للاختبار دون الاستهزاء كله خدمة WCF منذ المكالمات إلى صندوق رأس المال العامل بحاجة إلى إدارة الاتصال.المكالمات في هذا ViewModel تبدو مثل هذا:

List<Sam.Alyza.WcfInterface.Website> rc = null;
Service<Sam.Alyza.WcfInterface.IServiceWebsites>.Use(alyzaSvc =>
{
  rc = new List<Sam.Alyza.WcfInterface.Website>(alyzaSvc.GetSites());
});

على ViewModel قابلة للاختبار حاولت إضافة منفصل عثر مجردة WCF اتصال بعيدا.بعد هذا ViewModel كانت قابلة للاختبار ، يدعو يشبه هذا:

List<Sam.Alyza.WcfInterface.Website> rc = new List<Sam.Alyza.WcfInterface.Website>(_datamodel.GetSites());

المشكلة:معظم التعليمات البرمجية التي سوف تحتاج إلى اختبار الآن قد انتقلت إلى عثر ، ، مرة أخرى ، في حاجة إلى تمويل رأس المال العامل لفحصها.ما بقي في ViewModel كانت قشرة رقيقة ، والتي يمكن اختبارها.ولكن منذ الرئيسية رمز انتقلت إلى عثر لذا اختبار ViewModel كانت عديمة الفائدة تماما.

لذا يبدو لي إضافة منفصل عثر طبقة إلى عرض / ViewModel التطبيق باستخدام صندوق رأس المال العامل لا تضيف الكثير من العمل, ولكن الاختبار لا تحصل على أي أفضل.

هل كانت مفيدة؟

المحلول

Woot بعد يومين من wacking بعيدا في هذه المشكلة وجدت حلا أستطيع العيش مع:

كما رأينا في المثال التعليمات البرمجية أعلاه, يمكنني استخدام هذه الفئة المساعد لإدارة بلدي WCF اتصال (بسبب التعامل السليم مع إغلاق مقابل إحباط):

public delegate void UseServiceDelegate<T>(T proxy);

public static class Service<T>
{
  public static ChannelFactory<T> _channelFactory;

  public static void Use(UseServiceDelegate<T> codeBlock)
  {
    if (_channelFactory == null)
      _channelFactory = new ChannelFactory<T>("AlyzaServiceEndpoint");
    IClientChannel proxy = (IClientChannel)_channelFactory.CreateChannel();
    bool success = false;
    try
    {
      codeBlock((T)proxy);
      proxy.Close();
      success = true;
    }
    finally
    {
      if (!success)
      {
        proxy.Abort();
      }
    }
  }
}

كما رأينا في سؤالي, هذه هي الطريقة التي يتم استخدام هذه الفئة في ViewModel:

Service<Sam.Alyza.WcfInterface.IServiceWebsites>.Use(alyzaSvc =>
{
  rc = new List<Sam.Alyza.WcfInterface.Website>(alyzaSvc.GetSites());
});

السخرية WCF واجهة سوف تحتاج إلى إنشاء واستضافة وهمية خدمة WCF تغيير كافة سلاسل اتصال.الكثير من العمل فقط لإضافة بعض الاختبارات.

لقد وجدت طريقة أسهل:أنها بسيطة إلى إنشاء نموذج خدمة تنفيذ واجهة:

public class MockWebsiteService : WcfInterface.IServiceWebsites
{
  internal List<Sam.Alyza.WcfInterface.Website> _websites = new List<Sam.Alyza.WcfInterface.Website>();
  internal int _GetSitesCallCount;

  IEnumerable<Sam.Alyza.WcfInterface.Website> Sam.Alyza.WcfInterface.IServiceWebsites.GetSites()
  {
    _GetSitesCallCount++;
    return _websites;
  }
}

المشكلة الوحيدة هي: كيف يمكنني جعل ViewModel المكالمة الوهمية الدرجة بدلا من الخدمة ؟
الحل:الخدمة.استخدام() لا يتمكنون من الاتصال.عن طريق إضافة وظائف إلى تجاوز إدارة الاتصال أنا قادرة على التسلل بلدي WCF كائن وهمي في الخدمة.استخدام().
لهذا أنا بحاجة إلى وسيلة لجعل الخدمة.استخدام() استدعاء شيء آخر غير صندوق رأس المال العامل (انظر في #تصحيح الفروع):

public static class Service<T>
{
#if DEBUG
  public static T DebugOverride = default(T);
#endif
  public static ChannelFactory<T> _channelFactory;

  public static void Use(UseServiceDelegate<T> codeBlock)
  {
#if DEBUG
    if (!Object.Equals(DebugOverride, default(T)))
    {
      codeBlock(DebugOverride);
      return;
    }
#endif
    if (_channelFactory == null)
      _channelFactory = new ChannelFactory<T>("AlyzaServiceEndpoint");
    IClientChannel proxy = (IClientChannel)_channelFactory.CreateChannel();
    bool success = false;
    try
    {
      codeBlock((T)proxy);
      proxy.Close();
      success = true;
    }
    finally
    {
      if (!success)
      {
        proxy.Abort();
      }
    }
  }
}

عن طريق إضافة هذا الاختبار هوك في الخدمة ، أنا قادرة على التسلل في أي كائن تنفيذ T في الاختبارات:

MockWebsiteService mockmodel = new MockWebsiteService();
Service<WcfInterface.IServiceWebsites>.DebugOverride = mockmodel;
// run my tests here

بالنسبة لي هذا هو وسيلة جيدة جدا أن يسخر خدمة WCF!

PS:أنا على علم بسبب #إذا كان تصحيح الاختبارات سوف يتم ترجمة في الافراج عنهم.فقط بطردهم إذا كنت الرعاية.

نصائح أخرى

ونحن نستخدم التبعية حقن لمعالجة هذه المشكلة، حقن عميل خدمة (أو ربما مصنع لخدمة العملاء) في ViewModel. شيء من هذا القبيل:

interface IClientFactory
{
    TClient CreateClient<TClient>();
}

class ClientFactory : IClientFactory
{
    TClient CreateClient<TClient>() 
    {
       var channelFactory = new ChannelFactory<TClient>("AlyzaServiceEndpoint");
       var proxy = (TClient)channelFactory.CreateChannel();
       return proxy;
    }
}

public ViewModel 
{
    public ViewModel(IClientFactory clientFactory)
    {
       _clientFactory = clientFactory;
    }

    private void DoWcfStuff()
    {
        using (var proxy = _clientFactory.CreateClient<IClientChannel>())
        {
           var result = proxy.GetThings();
        }
    }
}

public ViewModelTests
{
    public void Setup()
    {
       _mockFactory = new MockClientFactory();
       _viewModel = new ViewModel(_mockFactory);
    }

    [Test]
    public void Test() 
    {
       var testResult = new Result();
       var mockClient = _mockFactory.CreateClient<IClientChannel>();

       mockClient.SetResultForGetThings(testResult);

       // put the viewmodel through its paces.
    }

    private class MockClientFactory : IClientFactory
    {
        MockClient _mockClient;

        public MockClientFactory()
        {
          _mockClient = new MockClient();
        }

        public TClient CreateClient<TClient>()
        {
           if (typeof(TClient) == typeof(IClientChannel))
           {
              return _mockClient;
           }
        }
    }

    private class MockClient : IClientChannel
    {
        void SetupGetThingsResult(Result result)
        {
           _result = result;
        }

        Result GetThings() 
        {
           return _result;
        }
    }
}

ولقد أظهرت مثال باستخدام يسخر جهة رمز. عادة ما أود أن استخدام إطار ساخرا مثل موك .

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top