【问题标题】:How to mock or fake HttpApplication / HttpContext for testing如何模拟或伪造 HttpApplication / HttpContext 进行测试
【发布时间】:2014-01-01 18:37:42
【问题描述】:

我正在尝试在我的 MVC 应用程序上运行一些测试,但我遇到了一个无法让它工作的世界。我会尽量直入主题:

我正在使用 RhinoMocks 来尝试这样的事情:

设置:

MockRepository mocks = new MockRepository();
HttpContextBase _mockContext = mocks.FakeHttpContext();
mocks.SetFakeControllerContext(new LoginController());
HttpApplicationStateBase appState = MockRepository.GenerateStub<HttpApplicationStateBase>();
_mockContext.Expect(mc => mc.Application).Return(appState);
HttpContext.Current = _mockContext.ApplicationInstance.Context;

这是FakeHttpContext() 方法:

public static HttpContextBase FakeHttpContext(this MockRepository mocks)
{
    HttpApplication app = mocks.PartialMock<HttpApplication>();

    HttpContextBase context = mocks.PartialMock<HttpContextBase>();
    HttpRequestBase request = mocks.PartialMock<HttpRequestBase>();
    HttpResponseBase response = mocks.PartialMock<HttpResponseBase>();
    HttpSessionStateBase session = mocks.PartialMock<HttpSessionStateBase>();
    HttpServerUtilityBase server = mocks.PartialMock<HttpServerUtilityBase>();

    SetupResult.For(context.ApplicationInstance).Return(app);

    SetupResult.For(context.Request).Return(request);
    SetupResult.For(context.Response).Return(response);
    SetupResult.For(context.Session).Return(session);
    SetupResult.For(context.Server).Return(server);

    mocks.Replay(context);
    return context;
}

我确实需要访问HttpContextBase.Request.AppRelativeCurrentExecutionFilePath,但它总是返回为nullHttpContext.Current.Request.RequestContext 也是如此。

有人可以帮我吗?可以肯定地说我现在很绝望。

【问题讨论】:

  • 你不知道是什么问题吗?你得到一个错误(哪一个?)?据我所见,特定设置Setup(c =&gt; c.Request.AppRelativeCurrentExecutionFilePath) 应该可以工作,因为Request 是一个virtual 属性,它本身具有virtual 属性AppRelativeCurrentExecutionFilePath。你说_mockContext.SetupAllProperties();的原因是什么?您是否也希望设置其他属性?
  • @JeppeStigNielsen 我用我现在使用的东西更新了我的问题。我仍然无法让它工作。

标签: c# asp.net-mvc-4 integration-testing moq httpcontext


【解决方案1】:

为什么不创建一个包含对 HttpContext 基础的调用的抽象类?

然后你可以这样做:

public class MyClass
{
   private readonly IHttpContext _httpContext;
   MyClass(IHttpContext httpContext)
   {
       _httpContext = httpContext;
   }

   public void Blaat()
   {
        _httpContext.DoYourThingsWithTheHttpContext();
    }
}

假设您使用的是依赖注入,否则请查看 Microsoft 的 Fakes and Stubs 框架。

【讨论】:

    【解决方案2】:

    首先,尽量避免使用 HttpContext.Current,因为使用静态方法会使测试变得更加困难,正如您现在发现的那样。如果您使用的是依赖注入框架,请将 HttpContextBase 注入到您的构造函数中。

    对于你的实际问题,在FakeHttpContext()尝试改变

     HttpRequestBase request = mocks.PartialMock<HttpRequestBase>();
    

     HttpRequestBase request = mocks.GenerateStub<HttpRequestBase>();
    

    然后在您的测试中,您可以执行以下操作:

    _mockContext.Request.Stub(x=> x.AppRelativeCurrentExecutionFilePath).Return("foo");
    var result = object.DoSomething();
    Assert.AreEqual("foo",result);
    

    我认为对 HttpContext 进行部分模拟不是很有用,因为您将改为测试框架(即测试框架是否根据 HttpContext 中的值 Y 和 Z 返回正确的值 X)

    另一种选择是围绕 HttpContextBase 创建一个包装类,它将返回计算值。例如。 HttpContextBaseWrapper.AppRelativeCurrentExecutionFilePath()HttpContextBaseWrapper.RequestIpAddress()。这将使您的所有其他类的测试变得不那么复杂,因为他们不必担心模拟 HttpContextBase 和细节,他们只需模拟您的 HttpContextBaseWrapper 类。

    编辑:

    我还建议您也注入您的 HttpRequestContext,但如果这不可能,那么您可以像这样在 FakeHttpContext 方法中存根 RequestContext:

    var requestContext = MockRepository.GenerateStub<RequestContext>();
    request.RequestContext = requestContext;
    

    【讨论】:

    • 我非常感谢这个答案。我编辑了 OP,因为我遇到了另一个问题。我还需要模拟HttpContext.Current.Request.RequestContext。你有没有机会帮我解决这个问题?
    • 我已经更新了我的答案以允许您存根 RequestContext。
    • 我不太确定HttpRequestContext 是什么。我假设你的意思是RequestContext。再次感谢!我会试试看效果如何。
    • @kehrk HttpRequestContextRequestContext 属性的类型
    • 我没有看到任何HttpRequestContext,但我确实看到了RequestContext
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-17
    • 1970-01-01
    • 1970-01-01
    • 2014-01-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多