如何模拟或伪造HttpApplication / HttpContext进行测试

时间:2013-12-13 20:59:33

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

我正在尝试在我的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,但它始终以null的形式返回。 HttpContext.Current.Request.RequestContext也是如此。

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

2 个答案:

答案 0 :(得分:1)

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

然后你可以这样做:

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

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

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

答案 1 :(得分:1)

首先,尝试避免使用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;