单元测试 - 如何使用最小起订量来最小化 WCF 客户端

Unit Test - How to MOQ WCF Client using MOQ

我一直在看 many other questions on SO,很多类似的,但是 none 似乎符合服务参考的风格,所以我问。大部分都说用ChannelFactory,这个用的是ClientBase。我正在了解有关单元测试和最小起订量的更多信息。我想测试我们的存储库 class,它调用 WCF 服务。

我试过很多方法来模拟,包括在 repo 上创建一个构造函数,采用 FISP 接口。

我怎样才能使它在 repo 中可用并可进行单元测试,使用 moq 模拟 WCF 操作?

repository 没有传入接口(还),如下。它正在使用代理客户端 class.

public class FisPRepository : IFisPRepository
{
    private readonly FISPClient _fisPClient;

    public FisPRepository()
    {
        _fisPClient = new FISPClient
        {
            ClientCredentials =
            {

                UserName = {UserName = "xyz", Password = "cba"}
            }
        };

    public person GetPersonFromId(string id)
    {
        return _fisPClient.getPerson(new personRequest()
        {
            reference = new referenceFilter { type = "FWI", value = id },
        });
    }
}

生成参考

这是生成的参考代码 -

接口:

    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace="http://www.aUrl.com/fwi", ConfigurationName="FISP.FISP")]
public interface FISP {
    [System.ServiceModel.OperationContractAttribute(Action="http://www.aUrl.com/fwi/FISP/getPersonRequest", ReplyAction="http://www.aUrl.com/fwi/FISP/getPersonResponse")]
    [System.ServiceModel.FaultContractAttribute(typeof(FhSoap.FISP.FWiException), Action="http://www.aUrl.com/fwi/FISP/getPerson/Fault/FWiException", Name="FWiException")]
    [System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults=true)]
    [System.ServiceModel.ServiceKnownTypeAttribute(typeof(episodeTask))]
    [return: System.ServiceModel.MessageParameterAttribute(Name="person")]
    FhSoap.FISP.getPersonResponse getPerson(FhSoap.FISP.getPersonRequest request);  
}

客户:

    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
public interface FISPChannel : FhSoap.FISP.FISP, System.ServiceModel.IClientChannel {
}

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
public partial class FISPClient : System.ServiceModel.ClientBase<FhSoap.FISP.FISP>, FhSoap.FISP.FISP {
    public FISPClient() {
    }

    public FISPClient(string endpointConfigurationName) : 
            base(endpointConfigurationName) {
    }

    [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
    FhSoap.FISP.getPersonResponse FhSoap.FISP.FISP.getPerson(FhSoap.FISP.getPersonRequest request) {
        return base.Channel.getPerson(request);
    }

    public FhSoap.FISP.person getPerson(FhSoap.FISP.personRequest request) {
        FhSoap.FISP.getPersonRequest inValue = new FhSoap.FISP.getPersonRequest();
        inValue.request = request;
        FhSoap.FISP.getPersonResponse retVal = ((FhSoap.FISP.FISP)(this)).getPerson(inValue);
        return retVal.person;
    }
}

更新

根据下面评论中的建议,我尝试使用接口构建客户端,是什么意思?因为这不会创建客户端,它会创建一个通道。

    public FisPRepository()
    {
        var factory = new ChannelFactory<FISPChannel>("BasicHttpBinding_SomthingService");

        var credentialBehaviour = factory.Endpoint.Behaviors.Find<ClientCredentials>();
        credentialBehaviour.UserName.UserName = "xyz";
        credentialBehaviour.UserName.Password = "cba";

        _fisPClient = factory.CreateChannel();
    }

_fisPClient = factory.CreateChannel(); 无效,因为它创建的是 FISPChannel,而不是客户端。我错过了什么?

your repository is working with your concrete client, you need to inject the client into the class onto an interface

回复:

@Kritner, The FISPChannel? As opposed to the FISP interface?

好吧,通常的约定是接口 "I" 类似于 IFISP,但无论哪种方式,IFISP 接口都是我过去使用的接口(而不是IFISPChannel 的。虽然目前,如果您尝试使用 FISP,该界面将无法访问您当前在 class 中设置的 ClientCredentials启动客户端。

理想情况下,您不会在每个存储库上设置凭据,而是在某种配置中。完成后,您可以重构为如下内容:

public class FisPRepository : IFisPRepository
{
    private readonly FISP _fisp;

    public FisPRepository(FISP fisp)
    {
        _fisp = fisp;
    }

    public person GetPersonFromId(string id)
    {
        return _fisP.getPerson(new personRequest()
        {
            reference = new referenceFilter { type = "FWI", value = id },
        });
    }
}

当然,在构建存储库时,您需要传递客户端的具体信息 - 但对于单元测试,您将能够模拟 FISP.

您可以通过多种方式了解客户。

  • 使用像 Ninject、Unity、AutoFac 等 IOC 容器
  • 直接新建实体
  • 使用服务位置

由于语法因您的 IOC 或服务位置而异,因此您现在可以通过以下方式直接获取存储库:

FisPRepository myRepo = new FisPRepository(new FISPClient());

将您的具体化和编码注入抽象是一种 design pattern 称为依赖注入。