如何使用起订量来嘲弄WCF客户端? [英] How to mock WCF client using Moq?

查看:128
本文介绍了如何使用起订量来嘲弄WCF客户端?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的项目,我使用:SL5 + MVVM +棱​​镜+ WCF + RX +起订量+ Silverlight的单元测试框架。

In my project I am using: SL5+ MVVM+ Prism + WCF + Rx + Moq + Silverlight Unit Testing Framework.

我是新来的单元测试,最近已经开始进入DI,模式(MVVM)等。因此以下code具有改善了很多范围(请随意拒收全部方法我正在下降,如果你这么认为)。

I am new to unit-testing and have recently started into DI, Patterns (MVVM) etc. Hence the following code has a lot of scope for improvement (please fell free to reject the whole approach I am taking if you think so).

要访问我的WCF服务,我创建了类似下面一个工厂类(再次,它可以是有缺陷的,但请看看):

To access my WCF services, I have created a factory class like below (again, it can be flawed, but please have a look):

namespace SomeSolution
{
    public class ServiceClientFactory:IServiceClientFactory
    {
        public CourseServiceClient GetCourseServiceClient()
        {
            var client = new CourseServiceClient();
            client.ChannelFactory.Faulted += (s, e) => client.Abort();
            if(client.State== CommunicationState.Closed){client.InnerChannel.Open();}
            return client;
        }

        public ConfigServiceClient GetConfigServiceClient()
        {
            var client = new ConfigServiceClient();
            client.ChannelFactory.Faulted += (s, e) => client.Abort();
            if (client.State == CommunicationState.Closed) { client.InnerChannel.Open(); }
            return client;
        }

        public ContactServiceClient GetContactServiceClient()
        {
            var client = new ContactServiceClient();
            client.ChannelFactory.Faulted += (s, e) => client.Abort();
            if (client.State == CommunicationState.Closed) { client.InnerChannel.Open(); }
            return client;
        }
    }
}

它实现了一个简单的界面,如下图:

It implements a simple interface as below:

public interface IServiceClientFactory
{
    CourseServiceClient GetCourseServiceClient();
    ConfigServiceClient GetConfigServiceClient();
    ContactServiceClient GetContactServiceClient();
}

在我的虚拟机我做上面的类的DI和使用接收到如下调用WCF:

In my VMs I am doing DI of the above class and using Rx to call WCF as below:

var client = _serviceClientFactory.GetContactServiceClient();
try
{

    IObservable<IEvent<GetContactByIdCompletedEventArgs>> observable =
        Observable.FromEvent<GetContactByIdCompletedEventArgs>(client, "GetContactByIdCompleted").Take(1);

    observable.Subscribe(
        e =>
            {
                if (e.EventArgs.Error == null)
                {                                    
                    //some code here that needs to be unit-tested

                }
            },
        ex =>
        {
            _errorLogger.ProcessError(GetType().Name, MethodBase.GetCurrentMethod().Name, ErrorSource.Observable, "", -1, ex);
        }
        );
    client.GetContactByIdAsync(contactid, UserInformation.SecurityToken);
}
catch (Exception ex)
{
    _errorLogger.ProcessError(GetType().Name, MethodBase.GetCurrentMethod().Name, ErrorSource.Code, "", -1, ex);
}

现在我想建立单元测试(是的,它不是TDD)。但我不明白的地方开始。随着起订量,我不能嘲笑BlahServiceClient。还没有SvcUtil工具生成的接口可以提供帮助,因为异步方法不自动生成的IBlahService接口的一部分。我可以preFER扩展(通过部分类等)的任何自动生成的类,但我不想选择手动构建所有code,它SvcUtil工具可以生成(坦率地考虑时间和预算)。

Now I want to build unit tests (yes, its not TDD). But I don't understand where to start. With Moq I can't mock the BlahServiceClient. Also no svcutil generated interface can help because async methods are not part of the auto-generated IBlahService interface. I may prefer to extend (through partial classes etc) any of the auto generated classes, but I would hate to opt for manually building all the code that svcutil can generate (frankly considering time and budget).

可有人请帮忙吗?在正确的方向指向任何能帮助我很多东西。

Can someone please help? Any pointer in the right direction would help me a lot.

推荐答案

在嘲笑你的​​服务客户端,你实际上是嘲讽它实现的接口之一。所以你的情况可能是 IContactService

When mocking your service client you are actually mocking one of the interfaces it implements. So in your case it may be IContactService.

生成的code同时实现了 System.ServiceModel.ClientBase&LT; IContactService&GT; IContactService 。你的依赖供应商(在你的情况下,工厂)将返回 ContactServiceClient - 对于初学者将其更改为 IContactService 。这在现在和未来将帮助你DI

The generated code implements both System.ServiceModel.ClientBase<IContactService> and IContactService. Your dependency provider (in your case a factory) is returning ContactServiceClient - change this to IContactService for starters. This will aid your DI now and in the future.

好吧,你已经有一个抽象工厂,现在他们回到服务接口 IContactService 。您正在使用的接口只有现在这么嘲讽是很平凡的。

Ok, you're already have an abstract factory and now they return your service interface IContactService. You're using interfaces only now so the mocking is quite trivial.

首先,一些关于code你想行使的假设。在code段提供的消息无论是抽象工厂和服务客户​​端。只要在 //一些$ C $这里C,它需要进行单元测试部分不会与任何其他的依赖互动,那么你正在寻找模拟出工厂和服务客户​​,让您的测试是孤立只方法体code两者。

First some assumptions about the code you're trying to exercise. The code snippet provided messages both the abstract factory and the service client. Provided that the //some code here that needs to be unit-tested section is not going to interact with any other dependencies then you're looking to mock out both the factory and the service client so that you test is isolated to just the method body code.

我做了例如着想调整。您的接口:

I've made an adjustment for the sake of example. Your interfaces:

public class Contact {
    public string Name { get; set; }
}

public interface IContactService {
    Contact GetContactById(int contactid);
}

public interface IContactServiceFactory {
    IContactService GetContactService();
}

那么你的测试看起来总结是这样的:

Then your test would look summing like this:

public void WhateverIsToBeTested_ActuallyDoesWhatItMustDo() {

    // Arrange
    var mockContactService = new Mock<IContactService>();
    mockContactService.Setup(cs => cs.GetContactById(It.IsAny<int>()))
        .Returns(new Contact { Name = "Frank Borland" });

    var fakeFactory = new Mock<IContactServiceFactory>();
    fakeFactory.Setup(f => f.GetContactService())
        .Returns(mockContactService.Object);

    /* i'm assuming here that you're injecting the dependency intoto your factory via the contructor - but 
     * assumptions had to be made as not all the code was provided
     */
    var yourObjectUnderTest = new MysteryClass(fakeFactory.Object);

    // Act
    yourObjectUnderTest.yourMysteryMethod();

    // Assert
    /* something mysterious, but expected, happened */            

}

编辑:嘲讽异步方法

异步生成的方法是不是你的服务方法的一部分,是由WCF创建为客户端类的一部分。嘲笑那些作为一个接口来执行以下操作:

The async generated methods are not part of your service methods and is created by WCF as part of the Client class. To mock those as an Interface do the following:


  1. 提取 ContactServiceClient 类的接口。在VS它只是一个右键单击(在类名),重构,提取接口。而且只选择适用的方法。

  1. Extract the Interface of the ContactServiceClient class. In VS it's simply a right-click (on the class name), refactor, extract interface. And choose only the applicable methods.

ContactServiceClient 类偏因此创建一个新的类文件并重新定义ContactServiceClient类来实现新的 IContactServiceClient 界面,你刚才提取。

The ContactServiceClient class is partial so create a new class file and redefine the ContactServiceClient class to implement the new IContactServiceClient interface you just extracted.

public partial class ContactServiceClient : IContactServiceClient {
}


喜欢这样现在的客户端类也实现与选定的异步方法的新界面。当刷新服务接口并重新生成服务类 - 你不必重新提取接口已经创建了一个的独立的部分类的与接口引用

Like such and now the client class ALSO implements the new interface with the selected async methods. When refreshing your service interface and the service class is re-generated - you don't have to re-extract the interface as you've created a separate partial class with the interface reference.

创建一个新的工厂,返回新界面

  1. Create a new factory to return the new interface

public interface IContactServiceClientFactory {
    IContactServiceClient GetContactServiceClient();
}


  • 修改测试与该接口工作。

  • Modify the test to work with that interface.

    这篇关于如何使用起订量来嘲弄WCF客户端?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆