8

I am trying to get a unit test(more of an integration test) written for the GetAwesomeResultsAsXml() for the following WCF Rest Service.
How do I deal with the WebOperationContext mocking aspect?
What would be the best approach?

public class AwesomeRestService : AwesomeRestServiceBase, IAwesomeRestService
    {
        public AwesomeSearchResults<AwesomeProductBase> GetAwesomeResultsAsXml()
        {
            return GetResults();
        }

        private static AwesomeSearchResults<AwesomeProductBase> GetResults()
        {
            var searchContext = AwesomeSearchContext
                               .Parse(WebOperationContext.Current);
            ..............
            ..............
            ..............
        }


    }

[ServiceContract]
    public interface IAwesomeRestService
    {
        [OperationContract]
        [WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Xml,
        BodyStyle =  WebMessageBodyStyle.Bare,
            UriTemplate = "/search/xml")]
        AwesomeQueryResults<AwesomeProductBase> GetAwesomeResultsAsXml();


    }







public class AwesomeSearchContext
        {
            ................
            ................
            ................
             public static AwesomeSearchContext Parse 
                                           (WebOperationContext operationContext)
            {
                return WebOperationContext.Current != null ? new     
 AwesomeSearchContext(operationContext.IncomingRequest.UriTemplateMatch.QueryParameters) : null;
            }
        }
GilliVilla
  • 4,998
  • 11
  • 55
  • 96

5 Answers5

9

I met the same problem. I want to unit test a WCF service function (for IOauth2 interface as below example) without any IIS. This is the code snippet for the preparation.

// Prepare WebOperationContext
var factory = new ChannelFactory<IOauth2>(
    new WebHttpBinding(),
    new EndpointAddress("http://localhost:80"));

OperationContext.Current = new OperationContext(factory.CreateChannel() as IContextChannel);
Debug.Assert(WebOperationContext.Current != null);
Qi Luo
  • 841
  • 10
  • 15
3

I followed Sanjay's answer, and try the MS fake framework,

First of all, you have to open "Solution Explorer > your test project > Reference" => right-click the "System.ServiceModel.Web" => press "add Fakes Assembly"

Reference:

using Microsoft.QualityTools.Testing.Fakes;
using System.ServiceModel.Web.Fakes;

Sample:

using (ShimsContext.Create())
{
    var response = new ShimOutgoingWebResponseContext();
    var request = new ShimIncomingWebRequestContext();

    var ctx_hd = new WebHeaderCollection();
    ctx_hd.Add("myCustomHeader", "XXXX");
    request.HeadersGet = () => ctx_hd;

    var ctx = new ShimWebOperationContext
    {
        OutgoingResponseGet = () => response,
        IncomingRequestGet = () => request
    };
    ShimWebOperationContext.CurrentGet = () => ctx;

    //Test your code here...
}

and now you can get the WebOperationContext.Current.IncomingRequest.Headers["myCustomHeader"] in your WCF service code now.

More about MS Fakes framework on MSDN: https://msdn.microsoft.com/en-us/library/hh549176.aspx

John Jang
  • 2,567
  • 24
  • 28
  • ShimsContext.Create() is giving NullReference exception. `StackTrace: at Microsoft.QualityTools.Testing.Fakes.UnitTestIsolation.TraceProfilerInstrumentationProvider.TraceProfilerMethods.ResolveProfilerPath() at Microsoft.QualityTools.Testing.Fakes.UnitTestIsolation.TraceProfilerInstrumentationProvider.TraceProfilerMethods..cctor()` – Nameless Sep 22 '17 at 07:03
  • 1
    How about trying to run VS as admin and run your test again? I got it from: https://stackoverflow.com/questions/44147376/unable-to-use-microsoft-fakes-in-vs2015-enterprise-cor-profiler-missing – John Jang Sep 22 '17 at 08:41
  • System.TypeInitializationException - {"The type initializer for 'TraceProfilerMethods' threw an exception."} – Nameless Sep 27 '17 at 04:59
  • Microsoft Fakes is unfortunately only available to Premium editions of Visual Studio. See here https://stackoverflow.com/a/18339061/1077279. – shamp00 Jan 26 '18 at 16:26
2

A common approach to this is mocking tool like moq (https://code.google.com/p/moq/) or rhinomocks.

As they don't allow you to mock static members you would need to wrap the call to webcontext.current. Here is an example of wrapping a static mmember and testing with moq: Mock static property with moq

Community
  • 1
  • 1
Phil Carson
  • 884
  • 8
  • 18
1

Likely overkill if you are not already using the MS Fakes framework, but if you are this works for me.

using (ShimsContext.Create())
        {

            var response = new ShimOutgoingWebResponseContext();
            var ctx = new ShimWebOperationContext
            {
                OutgoingResponseGet = () => response
            };

            ShimWebOperationContext.CurrentGet = () => ctx;

            try
            {
                ParameterInspector.BeforeCall("operationName", new string[]{"some_argument"} );
            }
            catch (Exception e)
            {
                Assert.IsNull(e);
            }
        }
Sanjay Uttam
  • 786
  • 1
  • 7
  • 19
  • Can you tell me where these (ShimOutgoingWebResponseContext and ShimWebOperationContext) are located? My code is not finding them and I am trying to determine which framework class(es) to include. I am already including the Microsoft.QualityTools.Testing.Fakes. – AdvApp Apr 02 '15 at 19:05
0

Create a client for your service, and then handle the OperationContext within the client:

public class AwesomeRestServiceClient : ClientBase<IAwesomeRestService>, IAwesomeRestService
{
    public class AwesomeRestServiceClient(string address)
        : base(new WebHttpBinding(), new EndpointAddress(address))
    {   
        this.Endpoint.EndpointBehaviors.Add(new WebHttpBehavior());
    }

    public AwesomeSearchResults<AwesomeProductBase> GetAwesomeResultsAsXml()
    {
        using (new OperationContextScope(this.InnerChannel))
        {
            return base.Channel.GetAwesomeResultsAsXml();
        }
    }
}

For further info on how to use this, see this answer.

codeMonkey
  • 4,134
  • 2
  • 31
  • 50