【问题标题】:How to mock WebOperationContext for unit testing?如何模拟 WebOperationContext 进行单元测试?
【发布时间】:2013-04-17 19:00:19
【问题描述】:

我正在尝试为以下 WCF 休息服务的GetAwesomeResultsAsXml() 编写单元测试(更多是集成测试)。
如何处理 WebOperationContext 模拟方面?
最好的方法是什么?

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

【问题讨论】:

  • 你想让你的测试做什么?

标签: c# wcf unit-testing rest weboperationcontext


【解决方案1】:

我遇到了同样的问题。我想在没有任何 IIS 的情况下对 WCF 服务功能(用于 IOauth2 接口,如下例)进行单元测试。这是代码sn -p 的准备工作。

// 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);

【讨论】:

    【解决方案2】:

    我按照Sanjay的回答,尝试了MS fake framework,

    首先,你必须open "Solution Explorer &gt; your test project &gt; Reference" => right-click the "System.ServiceModel.Web" => press "add Fakes Assembly"

    参考:

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

    示例:

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

    现在您可以在 WCF 服务代码中获取 WebOperationContext.Current.IncomingRequest.Headers["myCustomHeader"]。

    MSDN 上有关 MS Fakes 框架的更多信息: https://msdn.microsoft.com/en-us/library/hh549176.aspx

    【讨论】:

    • ShimsContext.Create() 给出 NullReference 异常。 StackTrace: at Microsoft.QualityTools.Testing.Fakes.UnitTestIsolation.TraceProfilerInstrumentationProvider.TraceProfilerMethods.ResolveProfilerPath() at Microsoft.QualityTools.Testing.Fakes.UnitTestIsolation.TraceProfilerInstrumentationProvider.TraceProfilerMethods..cctor()
    • 尝试以管理员身份运行 VS 并再次运行测试如何?我来自:stackoverflow.com/questions/44147376/…
    • System.TypeInitializationException - {"'TraceProfilerMethods' 的类型初始化器抛出异常。"}
    • 不幸的是,Microsoft Fakes 仅适用于 Visual Studio 的高级版。见这里stackoverflow.com/a/18339061/1077279
    【解决方案3】:

    一种常见的方法是模拟 moq (https://code.google.com/p/moq/) 或 rhinomocks 等工具。

    由于它们不允许您模拟静态成员,您需要包装对 webcontext.current 的调用。这是包装静态 mmember 并使用 moq 进行测试的示例:Mock static property with moq

    【讨论】:

      【解决方案4】:

      如果你还没有使用 MS Fakes 框架,这可能有点过头了,但如果你是这样的话,这对我有用。

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

      【讨论】:

      • 你能告诉我这些(ShimOutgoingWebResponseContext 和 ShimWebOperationContext)在哪里吗?我的代码没有找到它们,我正在尝试确定要包含的框架类。我已经包含了 Microsoft.QualityTools.Testing.Fakes。
      【解决方案5】:

      为您的服务创建一个客户端,然后在客户端中处理 OperationContext:

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

      有关如何使用它的更多信息,请参阅this answer

      【讨论】:

        猜你喜欢
        • 2018-04-04
        • 2021-09-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-08-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多