如何在单元测试中为FakeHttpContext设置Request.Header

18
我有一个名为FakeHttpContext的对象,我一直在尝试修改它以便包含一些用于测试目的的头部信息。
public static HttpContext FakeHttpContext()
{
    var httpRequest = new HttpRequest("", "http://stackoverflow/", "");
    var stringWriter = new StringWriter();
    var httpResponse = new HttpResponse(stringWriter);
    var httpContext = new HttpContext(httpRequest, httpResponse);   

    var sessionContainer = new HttpSessionStateContainer("id", new SessionStateItemCollection(),
                                                    new HttpStaticObjectsCollection(), 10, true,
                                                    HttpCookieMode.AutoDetect,
                                                    SessionStateMode.InProc, false);

    httpContext.Items["AspSession"] = typeof(HttpSessionState).GetConstructor(
                                        BindingFlags.NonPublic | BindingFlags.Instance,
                                        null, CallingConventions.Standard,
                                        new[] { typeof(HttpSessionStateContainer) },
                                        null)
                                .Invoke(new object[] { sessionContainer });

    return httpContext;
 }

这段代码在没有头部的情况下可以工作,但是当我在httpRequeststringWriter之间添加任何这些代码行时。
    httpRequest.Headers.Add("blah", "1234");
    httpRequest.Headers["blah"] = "1234";

它抛出异常

发生了一个类型为 'System.PlatformNotSupportedException' 的异常,位于 System.Web.dll 中,但在用户代码中没有被处理

  • 为什么会出现这个异常?
  • 有没有可能在测试 WebApi 控制器时向 HttpContext 添加头信息?

如果您可以让您的代码与HttpContextBase一起工作,那么通常可以模拟这样的事情(包括请求和请求标头)。通常,只要您不使用HttpContext.Current,这不应该是一个问题。 - Reddog
我尝试按照这个链接上的答案进行操作:https://dev59.com/hXVD5IYBdhLWcg3wRpeX,但似乎对于WebAPI控制器而言并不起作用,只适用于MVC控制器。 - Oluwafemi
2个回答

23

我正在使用 .Net Core 3.1 和 Moq 框架。我创建了一个 DefaultHttpContext,设置了其中的标头(header),最后将其分配给控制器(Controller) ControllerContext 构造函数。

var httpContext = new DefaultHttpContext();
httpContext.Request.Headers["X-Example"] = "test-header";
var controller = new ExampleController(mockClient.Object, mockLogger.Object) 
{ 
    ControllerContext = new ControllerContext()
    {
        HttpContext = httpContext
    }
};

来源: https://www.thecodebuzz.com/unit-test-mock-httprequest-in-asp-net-core-controller/


2
这个对我很有用,Controller.Request 是只读的 (.net core 5),不确定我是否漏掉了什么。 - John Irvine
请提供DefaultHttpContext类的设置代码。 - ayush mishra
1
它运行得非常好!谢谢@DMendonza - m4verick
@ayushmishra DefaultHttpContext类是Microsoft.AspNetCore.Http命名空间的一部分。以下是Microsoft关于它的文档链接: DefaultHttpContext Class - DMendoza
1
Net Core 3.1 的绝佳解决方案。 - toha

14

我刚刚发现,使用HttpRequestMessage类,你可以轻松地添加头信息来测试你的WebAPI控制器,而不需要创建任何虚拟的HttpContext

var request = new HttpRequestMessage(HttpMethod.Get, "http://stackoverflow");
request.Headers.Add("deviceId","1234");
_myController.Request = request;

17
“ControllerBase.Request” 属性或索引器无法赋值,因为它是只读的。 - Oliver Pearmain
在我的情况下不起作用。 - ayush mishra
@OliverPearmain Microsoft在后续版本中改变了WebAPI控制器的工作方式,这就是为什么它不起作用的原因。解决方案专门针对.Net 4.5,抱歉在回答或帖子中没有明确说明。https://learn.microsoft.com/en-us/dotnet/api/system.web.http.apicontroller.request?view=aspnet-webapi-5.2#system-web-http-apicontroller-request - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接