【问题标题】:Need to add custom header to request in unit test需要在单元测试中为请求添加自定义标头
【发布时间】:2013-08-22 17:31:51
【问题描述】:

通过在线查找一些代码,我终于能够使HttpContext.Current 不为空。但是我仍然无法在我的单元测试中向请求中添加自定义标头。这是我的测试:

[TestClass]
public class TagControllerTest
{
    private static Mock<IGenericService<Tag>> Service { get; set; }
    private TagController controller;

    [TestInitialize]
    public void ThingServiceTestSetUp()
    {
        Tag tag = new Tag(1, "people");
        Response<Tag> response = new Response<Tag>();
        response.PayLoad = new List<Tag>() { tag };

        Service = new Mock<IGenericService<Tag>>(MockBehavior.Default);
        Service.Setup(s => s.FindAll("username", "password", "token")).Returns(response);

        controller = new TagController(Service.Object);
        HttpContext.Current = FakeHttpContext();
    }

    public static HttpContext FakeHttpContext()
    {
        var httpRequest = new HttpRequest("", "http://kindermusik/", "");
        var stringWriter = new StringWriter();
        var httpResponce = new HttpResponse(stringWriter);
        var httpContext = new HttpContext(httpRequest, httpResponce);

        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 });
        httpContext.Request.Headers["username"] = "username"; //It throws a PlatformNotSupportedException exception
        httpContext.Request.Headers["password"] = "password"; //.Headers.Add("blah", "blah") throws same error
        httpContext.Request.Headers["token"] = "token"; //And so to .Headers.Set("blah", "blah")

        return httpContext;
    }

    [TestMethod]
    public void TagControllerGetTest()
    {
        // Arrange
        Response<Tag> result = controller.Get();

        // Assert
        Assert.AreEqual(true, result.IsSuccess);
        Assert.AreEqual(1, result.PayLoad.Count);
        Assert.AreEqual("people", result.PayLoad[0].Name);
    }

这是正在测试的代码。

public class TagController : ApiController
{
    public IGenericService<Tag> _service;

    public TagController()
    {
        _service = new TagService();
    }

    public TagController(IGenericService<Tag> service)
    {
        this._service = service;
    }

    // GET api/values
    public Response<Tag> Get()
    {
        HttpContext context = HttpContext.Current;
        string username = context.Request.Headers["username"].ToString();
        string password = context.Request.Headers["password"].ToString();
        string token = context.Request.Headers["token"].ToString();
        return (Response<Tag>) _service.FindAll(username, password, token);
    }
}

【问题讨论】:

    标签: c# unit-testing httprequest httpcontext asp.net-apicontroller


    【解决方案1】:

    您可以使用它,它适用于:

    Setting HttpContext.Current.Session in a unit test

    用户 Anthony 的回答,并在 GetMockedHttpContext 中添加此代码:

    request.SetupGet(req => req.Headers).Returns(new NameValueCollection());
    

    然后你可以添加:

    HttpContextFactory.Current.Request.Headers.Add(key, value);
    

    通过这个你可以发布标题。但不幸的是,您必须使用 HttpContextFactory 而不是 HttpContext

    【讨论】:

      【解决方案2】:

      感谢 Adam Reed 的博客,可以使用反射修改 Headers 集合:MOCK HTTPCONTEXT.CURRENT.REQUEST.HEADERS UNIT TEST

      HttpContext.Current = new HttpContext(
      new HttpRequest("", "http://tempuri.org", ""), new HttpResponse(new StringWriter()));
      
      NameValueCollection headers = HttpContext.Current.Request.Headers;
      
      Type t = headers.GetType();
      const BindingFlags nonPublicInstanceMethod = BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance;
      
      t.InvokeMember("MakeReadWrite", nonPublicInstanceMethod, null, headers, null);
      t.InvokeMember("InvalidateCachedArrays", nonPublicInstanceMethod, null, headers, null);
      
      // eg. add Basic Authorization header
      t.InvokeMember("BaseRemove", nonPublicInstanceMethod, null, headers, new object[] { "Authorization" });
      t.InvokeMember("BaseAdd", nonPublicInstanceMethod, null, headers, 
          new object[] { "Authorization", new ArrayList{"Basic " + api_key} });
      
      t.InvokeMember("MakeReadOnly", nonPublicInstanceMethod, null, headers, null);
      

      【讨论】:

        【解决方案3】:

        我相信在 API 控制器方法中你可以使用“Request”属性:

        var testValue = this.Request.Headers.GetValues("headerKey").FirstOrDefault();
        

        然后您可以通过这种方式在单元测试中添加测试值:

        var controller = new TestController();
        controller.Request = new HttpRequestMessage();
        controller.Request.Headers.Add("headerKey", "testValue");
        

        【讨论】:

        • 你不能设置controller.Request。你会得到一个错误。无法将属性或索引器“属性”分配给 -- 它是只读的
        猜你喜欢
        • 2013-11-13
        • 1970-01-01
        • 1970-01-01
        • 2020-03-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-11-14
        • 2012-11-15
        相关资源
        最近更新 更多