【问题标题】:mocking httpContext.Current Api controller unit test模拟 httpContext.Current Api 控制器单元测试
【发布时间】:2016-07-05 08:36:22
【问题描述】:

我正在尝试使用Moq framework 模拟httpContext,以在请求来自单元测试但无法真正使其正常工作时确保httContext.Current is not null

在使用 google 之后,我按照以下步骤进行操作,因此在我向Api controller 发出电话后不确定下一步是什么。

第一步

Add Moq package to project

第二步

using Moq;

第三步

var context = new Mock<HttpContextBase>();
var request = new Mock<HttpRequestBase>();
var response = new Mock<HttpResponseBase>();

request.Setup(r => r.UrlReferrer).Returns(new Uri("http://tempuri.org/?ReturnUrl=%2f"));
response.Setup(r => r.Cookies).Returns(new HttpCookieCollection());
context.Setup(c => c.Request).Returns(request.Object);
context.Setup(c => c.Response).Returns(response.Object);

在发出 Post 控制器请求之前,有人可以帮我完成接下来需要做的步骤吗?

【问题讨论】:

  • 您应该重构您的代码以将其与HttpContext 分离,使其更易于测试。不得不模拟你无法控制的事情通常会产生比它解决的问题更多的问题。尝试创建单元测试时遇到的困难程度直接表明您的代码构建得好坏。

标签: c# unit-testing asp.net-web-api2


【解决方案1】:

在您的情况下,编写集成测试可能要容易得多。

    [Test]
    public async Task get_should_succeed()
    {
        //arrange
        var url = string.Format("{0}{1}", BaseUrl, "controller");

        using(var httpServer = CreateHttpServer())
        using (var client = CreateHttpInvoker(httpServer))
        {
            using (var request = CreateHttpRequest(HttpMethod.Get, url))
            //act
            using (var response = await client.SendAsync(request, CancellationToken.None))
            {
                //assert
                Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
            }
        }
    }

ControllerTestBase 的简化版本:

public abstract class ControllerTestBase
{
    protected ControllerTestBase()
    {
        BaseUrl = "http://localhost/api/";
    }

    public string BaseUrl { get; set; }

    public static HttpServer CreateHttpServer()
    {
        var httpConfiguration = WebApiConfig.Register();
        return new HttpServer(httpConfiguration);
    }

    public static HttpMessageInvoker CreateHttpInvoker(HttpServer httpServer)
    {
        return new HttpMessageInvoker(httpServer);
    }

    public HttpRequestMessage CreateHttpRequest(HttpMethod httpMethod, string url)
    {
        return new HttpRequestMessage(httpMethod, url);
    }
}

【讨论】:

  • 我一句都没听懂你想说什么
  • 很抱歉,如果它足够清楚。基本上,通过使用此代码,您可以在内存中启动一个小型 Web 服务,从而可以定义输入然后断言输出。无耻推荐你查看这个:stephenzeng.com/Home/View/17
  • 所以您的意思是说编写集成测试(如您共享的链接中所述)将避免需要伪造 httpContext?对吗?
  • 没错。这样您就不需要模拟它,而测试环境仍然是孤立的,可以在您的 CI 流程中自动执行。
【解决方案2】:

首先,不要使用HttpContext.Current,因为它不支持单元测试。在您的Controller 中有RequestResponse 属性,可用于访问有关请求或响应的任何信息。使用它们而不是HttpContex.Current

在您的单元测试中,您可以设置自己的ControllerContext。请查看另一个 stackoverflow 问题,该问题描述了如何在 Web Api 中伪造 ControllerContext

Testing a Web API method that uses HttpContext.Current.Request.Files?

【讨论】:

  • HttpContext.Current怎么不支持单元测试? 2) 我如何使用 HttpContext、Request 和 Reponse 而不是 HttpContex.Current?
  • 另外,我可能不能做新的 ControllerContext 因为我有 web api 控制器而不是 MVC ..
  • 好的,没错。在 WebApi 中,您无法访问 HttpContext,但您需要了解的有关请求或响应的所有信息都可以从控制器的 RequestResponse 属性中接收。而且您仍然可以将自己的ControllerContext 设置为控制器,但是在WebApi 中,构造函数中不能有HttpContextBase
猜你喜欢
  • 1970-01-01
  • 2012-02-27
  • 2015-03-15
  • 2014-07-30
  • 2012-08-01
  • 1970-01-01
  • 2014-01-16
  • 2020-01-05
  • 1970-01-01
相关资源
最近更新 更多