如何模拟 OperationContext.Current (WCF 消息)

本文关键字:消息 Current WCF OperationContext 模拟 何模拟 | 更新日期: 2023-09-27 18:32:07

目前我面临着对生产代码进行单元测试的挑战。我们有一个函数,用于从传入的 WCF 消息中检索 IP 地址。

public void DoSomething(){
    var ipAddressFromMessage = GetIpFromWcfMessage();
    var IpAddress = IPAddress.Parse(ipAddressFromMessage);
    if(IpAddress.IsLoopback)
    {
        // do something 
    }
    else
    {
        // do something else
    }
}
private string GetIpFromWcfMessage()
{       
    OperationContext context = OperationContext.Current;
    string ip = ...//use the IP from context.IncomingMessageProperties to extract the ip
    return ip;    
}

问题是,我应该怎么做才能测试DoSomething()中的IP检查?

[Test]
Public void DoSomethingTest()
{
    //Arrange...
    // Mock OperationContext so that we can manipulate the ip address in the message
    // Assert.
    ...
}

我是否应该以某种方式更改使用操作上下文的方式,以便我可以模拟它(例如,实现接口并模拟接口的实现)?

如何模拟 OperationContext.Current (WCF 消息)

我会用静态助手包装调用:

public static class MessagePropertiesHelper
{
  private static Func<MessageProperties> _current = () => OperationContext.Current.IncomingMessageProperties;

  public static MessageProperties Current
  {
      get { return _current(); }
  }
  public static void SwitchCurrent(Func<MessageProperties> messageProperties)
  {
      _current = messageProperties;
  }
}

然后在GetIpFromWcfMessage我会打电话:

private string GetIpFromWcfMessage()
{       
    var props = MessagePropertiesHelper.Current;
    string ip = ...//use the IP from MessageProperties to extract the ip
    return ip;    
}

我将能够在测试场景中切换实现:

[Test]
Public void DoSomethingTest()
{
    //Arrange...
    // Mock MessageProperties so that we can manipulate the ip address in the message    
    MessagePropertiesHelper.SwitchCurrent(() => new MessageProperties());
    // Assert.
    ...
}

在这里你可以找到我对类似问题的回答:https://stackoverflow.com/a/27159831/2131067。

    public void AfterRequest_And_BeforeReply_ValidData_NoError()
    {           
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        ServiceHost host = new ServiceHost(typeof(MyService), new Uri(baseAddress));
        host.AddServiceEndpoint(typeof(IService), new BasicHttpBinding(), ""); //MyService class derives from IService
        // Arrange
        ChannelFactory<IService> factory = new ChannelFactory<IService>(new BasicHttpBinding(), new EndpointAddress(baseAddress));
        IService proxy = factory.CreateChannel();
        Mock<IContextChannel> contextChannel = new Mock<IContextChannel>();
        InstanceContext instanceContext = new InstanceContext(host);
        MessageVersion messageVersion = MessageVersion.Soap11;
        Message message = Message.CreateMessage(MessageVersion.Soap11, "GetUser");
        message.Headers.Add(MessageHeader.CreateHeader("UserId", "MyNamespace", "1001"));
        Mock<RequestContext> requestContext = new Mock<RequestContext>();
        requestContext.SetupGet(x => x.RequestMessage).Returns(message);
        Dictionary<string, string> keyValuePairs = new Dictionary<string, string>();
        keyValuePairs.Add("Id", "12345");
        OperationContext.Current = new OperationContext(factory.CreateChannel() as IContextChannel);
        MyServiceBehaviour serviceBehaviourObj = new MyServiceBehaviour();
        //Set up
        using (new OperationContextScope((IContextChannel)proxy))
        {
            OperationContext.Current.RequestContext = requestContext.Object;                
            EndpointDispatcher endpointDispatcher = new EndpointDispatcher(new EndpointAddress(baseAddress), "IService", "MyNamespace");
            OperationContext.Current.EndpointDispatcher = endpointDispatcher;
            DispatchOperation dispatchOperation = new DispatchOperation(OperationContext.Current.EndpointDispatcher.DispatchRuntime, "GetUser", "GetUser");
            OperationContext.Current.EndpointDispatcher.DispatchRuntime.Operations.Add(dispatchOperation);
            var request = serviceBehaviourObj.AfterReceiveRequest(ref message, null, instanceContext);
            serviceBehaviourObj.BeforeSendReply(ref message, null);   
        }
        ((IClientChannel)proxy).Close();
        factory.Close();
    //Assert
    Assert.IsTrue(message.IsFault == false);
  }