单元测试 - 如何使用最小起订量来最小化 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 称为依赖注入。
我一直在看 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 称为依赖注入。