2

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)?

forsvarir
  • 10,749
  • 6
  • 46
  • 77
haris hamdani
  • 1,367
  • 2
  • 11
  • 18

2 Answers2

6

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.

Community
  • 1
  • 1
tkestowicz
  • 332
  • 1
  • 4
  • 15
  • This would have been better as a comment to the question. "Link only answers" are frowned upon on stackoverflow as the site wants to "stand on its own two feet". Of course linking to SO itself still allows that, but the "low quality answer" hunters will likely flag this. – Marjan Venema Nov 28 '14 at 16:06
  • Thank you for the tip, I edited the answer. Now it has an example based on the question and additionally points to the similar answer. – tkestowicz Nov 29 '14 at 13:14
0
    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);
  }
Divya
  • 1
  • 1
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 08 '23 at 15:23
  • You should add explanation. – Super Kai - Kazuya Ito Jun 09 '23 at 09:36