How to mock OperationContext.Current (WCF Message)

4.4k views Asked by At

Currently I have a challenge to unit test a production code. We have a function to retrieve an IP address from an incoming WCF messages.

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;    
}

The question is, what should I do so that I could test the checking of the IP in the DoSomething()?

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

    // Assert.
    ...
}

Should I change the way I use the Operation context in a way so that I can mock it(e.g. implement an interface and mock the implementation of the interface)?

2

There are 2 answers

2
tkestowicz On

I would wrap the call with a static helper:

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;
  }

}

Then in GetIpFromWcfMessage I would call:

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

    return ip;    
}

And I would be able to switch the implementation in the test scenario:

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

    // Assert.
    ...
}

Here you can find my answer to similar problem: https://stackoverflow.com/a/27159831/2131067.

2
Divya On
    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);
  }