如何模拟 Visual Studio 自动生成的 SOAP 客户端?
How to mock SOAP client that was auto-generated by Visual Studio?
我有一个自动生成的 SOAP 客户端。它是由 visual studio 向导生成的(添加连接的服务 -> Microsoft WCF Web 服务引用提供程序)。我想模拟那个客户端,所以当一个方法被调用时,一个预定义的结果将以 SOAP 响应的格式返回。不幸的是,我无法让它工作 - 我的结果要么是 null(而不是在 .Returns 中定义),要么我得到一个异常。
我正在尝试在我的设计中应用简洁的架构。所以这个 SOAP 客户端进入了我的基础设施层,我已经为它创建了一个存储库。此存储库创建 DTO,因此可以将它们分派到我的持久性。存储库通过依赖注入接收 SOAP 客户端。我还想对存储库进行测试,只是为了验证 DTO 生成是否正确。所以,我想模拟这个 SOAP 服务,这样我就可以将它提供给存储库并测试返回的 DTO。
自动生成的界面:
public interface ApplicationSoap
{
[System.ServiceModel.OperationContractAttribute(Action = "http://Application/GetAppVersion", ReplyAction = "*")]
Task<ExtApp.GetAppVersionResponse> GetAppVersionAsync(ExtApp.GetAppVersionRequest request);
}
和自动生成的客户端class:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.1-preview-30514-0828")]
public partial class ApplicationSoapClient : System.ServiceModel.ClientBase<ExtApp.ApplicationSoap>, ExtApp.ApplicationSoap
{
static partial void ConfigureEndpoint(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, System.ServiceModel.Description.ClientCredentials clientCredentials);
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
System.Threading.Tasks.Task<ExtApp.GetAppVersionResponse> ExtApp.ApplicationSoap.GetAppVersionAsync(ExtApp.GetAppVersionRequest request)
{
return base.Channel.GetAppVersionAsync(request);
}
public System.Threading.Tasks.Task<ExtApp.GetAppVersionResponse> GetAppVersionAsync(int appVer)
{
ExtApp.GetAppVersionRequest inValue = new ExtApp.GetAppVersionRequest();
inValue.Body = new ExtApp.GetAppVersionRequestBody();
inValue.Body.appVer = appVer;
return ((ExtApp.ApplicationSoap)(this)).GetAppVersionAsync(inValue);
}
}
我想模拟 ApplicationSoapClient 和方法 GetApplicationVersionAsync。
经过不同的尝试,我在测试中得到了以下结果 class:
private ExtApp.AppVersion[] _response =
new ExtApp.AppVersion[]
{
new ExtApp.AppVersion
{
VersionNumber = 1,
StartDate = DateTime.Parse("2010-01-01"),
EndDate = DateTime.Parse("2015-12-31")
},
};
private Mock<ExtApp.ApplicationSoap> _client = new Mock<ExtApp.ApplicationSoap>();
public TestClass()
{
var body = new ExtApp.GetAppVersionRequestBody(It.IsAny<int>());
var request = new ExtApp.GetAppVersionRequestRequest(body);
_client
.Setup(s => s.GetAppVersionAsync(request))
.Returns(
Task.FromResult(
new ExtApp.GetAppVersionResponse(
new ExtApp.GetAppVersionResponseBody(_response)))
);
}
[Fact]
public void TestAppVersionDownload()
{
var request = new ExtApp.GetAppVersionRequest(
new ExtApp.GetAppVersionRequestBody(1));
var result = _clientSoap.Object.GetAppVersionAsync(request)
.Result; //returns null instead of defined in Returns section
Assert.True(result.Body.GetAppVersionResult.Length == 2);
}
它运行了,但是调用的结果是 null
。我期待取回具有非空 Body
属性 且内部包含数组的对象。我正在寻找如何使这个东西工作的建议。
您的 SOAP 客户端合同是:
public interface ApplicationSoap
{
[System.ServiceModel.OperationContractAttribute(Action = "http://Application/GetAppVersion", ReplyAction = "*")]
Task<ExtApp.GetAppVersionResponse> GetAppVersionAsync(ExtApp.GetAppVersionRequest request);
}
您将其用作存储库中的依赖项,可能如下所示:
public class Repository
{
private readonly IApplicationSoap _client;
public Repository(IApplicationSoap client) { _client = client; }
public async Task<AppVersion> GetAppVersionAsync(int version)
{
var request = new GetAppVersionRequest(new GetAppVersionRequestBody(version));
var response = await _client.GetAppVersionAsync(request);
return new AppVersion
{
Version = response.Body.Version,
StartDate = response.Body.StartDate,
EndDate = response.Body.EndDate
};
}
}
在这种情况下,您可能想要测试将输入转换为请求的代码以及将响应转换为 DTO 的代码。这是唯一属于 您的 的代码(而不是由工具生成)。为此,您需要在存储库测试中模拟(实际上 stub)SOAP 客户端合同,并使其 return 得到您想要的响应:
[Fact]
public async Task GetAppVersionAsync()
{
// arrange
var client = new Mock<IApplicationSoap>(); // mock the interface, not the class!
var result = new AppVersion
{
Version = 1,
StartDate = DateTime.Parse("2010-01-01"),
EndDate = DateTime.Parse("2015-12-31")
};
client.Setup(x => x.GetAppVersionAsync(It.IsAny<GetAppVersionRequest>))
.Returns(Task.FromResult(new GetAppVersionResponse(new GetAppVersionResponseBody(result))));
var repository = new Repository(soapApp);
// act
var dto = await repository.GetAppVersionAsync(1);
// assert (verify the DTO state)
Assert.Equal(1, dto.VersionNumber);
Assert.Equal(new DateTime(2010, 1, 1), dto.StartDate);
Assert.Equal(new DateTime(2015, 12, 31), dto.EndDate);
}
但是...仅仅因为您可以做到这一点并不意味着您应该这样做。
我有一个自动生成的 SOAP 客户端。它是由 visual studio 向导生成的(添加连接的服务 -> Microsoft WCF Web 服务引用提供程序)。我想模拟那个客户端,所以当一个方法被调用时,一个预定义的结果将以 SOAP 响应的格式返回。不幸的是,我无法让它工作 - 我的结果要么是 null(而不是在 .Returns 中定义),要么我得到一个异常。
我正在尝试在我的设计中应用简洁的架构。所以这个 SOAP 客户端进入了我的基础设施层,我已经为它创建了一个存储库。此存储库创建 DTO,因此可以将它们分派到我的持久性。存储库通过依赖注入接收 SOAP 客户端。我还想对存储库进行测试,只是为了验证 DTO 生成是否正确。所以,我想模拟这个 SOAP 服务,这样我就可以将它提供给存储库并测试返回的 DTO。
自动生成的界面:
public interface ApplicationSoap
{
[System.ServiceModel.OperationContractAttribute(Action = "http://Application/GetAppVersion", ReplyAction = "*")]
Task<ExtApp.GetAppVersionResponse> GetAppVersionAsync(ExtApp.GetAppVersionRequest request);
}
和自动生成的客户端class:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.1-preview-30514-0828")]
public partial class ApplicationSoapClient : System.ServiceModel.ClientBase<ExtApp.ApplicationSoap>, ExtApp.ApplicationSoap
{
static partial void ConfigureEndpoint(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, System.ServiceModel.Description.ClientCredentials clientCredentials);
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
System.Threading.Tasks.Task<ExtApp.GetAppVersionResponse> ExtApp.ApplicationSoap.GetAppVersionAsync(ExtApp.GetAppVersionRequest request)
{
return base.Channel.GetAppVersionAsync(request);
}
public System.Threading.Tasks.Task<ExtApp.GetAppVersionResponse> GetAppVersionAsync(int appVer)
{
ExtApp.GetAppVersionRequest inValue = new ExtApp.GetAppVersionRequest();
inValue.Body = new ExtApp.GetAppVersionRequestBody();
inValue.Body.appVer = appVer;
return ((ExtApp.ApplicationSoap)(this)).GetAppVersionAsync(inValue);
}
}
我想模拟 ApplicationSoapClient 和方法 GetApplicationVersionAsync。 经过不同的尝试,我在测试中得到了以下结果 class:
private ExtApp.AppVersion[] _response =
new ExtApp.AppVersion[]
{
new ExtApp.AppVersion
{
VersionNumber = 1,
StartDate = DateTime.Parse("2010-01-01"),
EndDate = DateTime.Parse("2015-12-31")
},
};
private Mock<ExtApp.ApplicationSoap> _client = new Mock<ExtApp.ApplicationSoap>();
public TestClass()
{
var body = new ExtApp.GetAppVersionRequestBody(It.IsAny<int>());
var request = new ExtApp.GetAppVersionRequestRequest(body);
_client
.Setup(s => s.GetAppVersionAsync(request))
.Returns(
Task.FromResult(
new ExtApp.GetAppVersionResponse(
new ExtApp.GetAppVersionResponseBody(_response)))
);
}
[Fact]
public void TestAppVersionDownload()
{
var request = new ExtApp.GetAppVersionRequest(
new ExtApp.GetAppVersionRequestBody(1));
var result = _clientSoap.Object.GetAppVersionAsync(request)
.Result; //returns null instead of defined in Returns section
Assert.True(result.Body.GetAppVersionResult.Length == 2);
}
它运行了,但是调用的结果是 null
。我期待取回具有非空 Body
属性 且内部包含数组的对象。我正在寻找如何使这个东西工作的建议。
您的 SOAP 客户端合同是:
public interface ApplicationSoap
{
[System.ServiceModel.OperationContractAttribute(Action = "http://Application/GetAppVersion", ReplyAction = "*")]
Task<ExtApp.GetAppVersionResponse> GetAppVersionAsync(ExtApp.GetAppVersionRequest request);
}
您将其用作存储库中的依赖项,可能如下所示:
public class Repository
{
private readonly IApplicationSoap _client;
public Repository(IApplicationSoap client) { _client = client; }
public async Task<AppVersion> GetAppVersionAsync(int version)
{
var request = new GetAppVersionRequest(new GetAppVersionRequestBody(version));
var response = await _client.GetAppVersionAsync(request);
return new AppVersion
{
Version = response.Body.Version,
StartDate = response.Body.StartDate,
EndDate = response.Body.EndDate
};
}
}
在这种情况下,您可能想要测试将输入转换为请求的代码以及将响应转换为 DTO 的代码。这是唯一属于 您的 的代码(而不是由工具生成)。为此,您需要在存储库测试中模拟(实际上 stub)SOAP 客户端合同,并使其 return 得到您想要的响应:
[Fact]
public async Task GetAppVersionAsync()
{
// arrange
var client = new Mock<IApplicationSoap>(); // mock the interface, not the class!
var result = new AppVersion
{
Version = 1,
StartDate = DateTime.Parse("2010-01-01"),
EndDate = DateTime.Parse("2015-12-31")
};
client.Setup(x => x.GetAppVersionAsync(It.IsAny<GetAppVersionRequest>))
.Returns(Task.FromResult(new GetAppVersionResponse(new GetAppVersionResponseBody(result))));
var repository = new Repository(soapApp);
// act
var dto = await repository.GetAppVersionAsync(1);
// assert (verify the DTO state)
Assert.Equal(1, dto.VersionNumber);
Assert.Equal(new DateTime(2010, 1, 1), dto.StartDate);
Assert.Equal(new DateTime(2015, 12, 31), dto.EndDate);
}
但是...仅仅因为您可以做到这一点并不意味着您应该这样做。