【发布时间】:2019-10-24 18:40:04
【问题描述】:
我们正在 XUnit 中为我们的 ASP.NET 应用程序项目之一创建单元测试。在项目中,我们试图模拟一个特定的第三方客户端,我们无法访问源代码并且不提供接口(只是我们可以创建的客户端对象)。为了解决这个问题,我们编写了一个包装类和该类的接口,以便我们可以模拟出该客户端所需的功能。这部分都很好。
我们在包装类和接口中创建的方法之一是 GetInnerChannel 方法,用于从客户端获取属性(我们想要模拟出来)。但是,该方法会从 System.ServiceModel 返回 IClientChannel 的接口。
public IClientChannel GetInnerChannel()
{
return client.InnerChannel;
}
这似乎无害,但在我们的模拟设置中,我们无法创建一个对我们正在测试的方法有用的假 IClientChannel 对象。这是我们的单元测试代码,用于澄清:
client.Setup(i => i.GetInnerChannel()).Returns(GetClientChannel());
在 Returns 调用中,您将看到我们正在返回一个方法 return,我们目前将其设置为 null。这是因为我们无法实例化接口。当我深入调试时,我发现在正常操作期间被送回代替接口的对象是 System.Runtime.Remoting.Proxies.__TransparentProxy 对象。对 __TransparentProxy 类的一点调查是它是一个内部密封类(这意味着我们不能在我们的单元测试代码中实例化它)。
很遗憾,我们正在测试的方法是这样使用 InnerChannel 的:
public List<EquifaxQuestion> GetEquifaxQuestions(User basicUserInfo, IEnumerable<AddressViewModel> Addresses)
{
try
{
InitialResponse response;
using (new OperationContextScope(client.GetInnerChannel()))
{
OperationContext.Current.OutgoingMessageHeaders.Add(
new EquifaxSecurityHeader(appID, username, password));
response = client.SubmitInitialInteraction(GenerateInitialRequest(basicUserInfo, Addresses));
}
如果我们可以替换 GetInnerChannel 调用,我不会这样做,因此我们需要模拟它才能通过单元测试,因为我们必须模拟我们的客户端。
还有其他方法可以返回对 GetInnerChannel() 有用的值或对象吗?我在模拟设置中错过了一步吗?还是 Moq 和其他模拟框架无法做我需要做的事情?还是我尝试单元测试的方法无法进行单元测试?提前谢谢你。
【问题讨论】:
-
为什么不能模拟
IClientChannel?类似var clientChannelMock = new Mock<IClientChannel>(); client.Setup(i => i.GetInnerChannel()).Returns(clientChannelMock); -
我试过了。问题出在我们正在测试的方法中,我们有以下行:
using (new OperationContextScope(client.GetInnerChannel())){ OperationContext.Current.OutgoingMessageHeaders.Add( new EquifaxSecurityHeader(appID, username, password));问题是 OperationContextScope 抛出错误Invalid IContextChannel passed to OperationContext. Must be either a server dispatching channel or a client proxy channel.另外,我们使用静态方法来设置标题(不能被嘲笑)。
标签: c# unit-testing moq xunit.net