【问题标题】:Mocking HttpContext.Current using moq on NUnit Test在 NUnit 测试中使用 moq 模拟 HttpContext.Current
【发布时间】:2012-10-02 18:02:13
【问题描述】:

我正在测试一个调用此类方法的 MVC 3 控制器:

public class SessionVar
{
    /// <summary>
    /// Gets the session.
    /// </summary>
    private static HttpSessionState Session
    {
        get
        {
            if (HttpContext.Current == null)
                throw new ApplicationException
                                   ("No Http Context, No Session to Get!");

            return HttpContext.Current.Session;
        }
    }

    public static T Get<T>(string key)
    {
        return Session[key] == null ? default(T) : (T)Session[key];
    }
    ...
}

我的测试方法,遵循Hanselman's Blog 的建议是:

[Test]
public void CanRenderEmployeeList()
{
    _mockIEmployeeService.Setup(s => s.GetEmployees(StatusFilter.OnlyActive))
        .Returns(BuildsEmployeeList().Where(e => e.IsApproved));

    var httpContext = FakeHttpContext();
    var target = _employeeController;
    target.ControllerContext = new ControllerContext
                  (new RequestContext(httpContext, new RouteData()), target);
    var result = target.Index();

    Assert.IsNotNull(result);
    Assert.IsInstanceOf<ViewResult>(result);
    var viewModel = target.ViewData.Model;
    Assert.IsInstanceOf<EmployeeListViewModel>(viewModel);
}

public static HttpContextBase FakeHttpContext()
{
    var context = new Mock<HttpContextBase>();
    var request = new Mock<HttpRequestBase>();
    var response = new Mock<HttpResponseBase>();
    var session = new Mock<HttpSessionStateBase>();
    var server = new Mock<HttpServerUtilityBase>();

    context.Setup(ctx => ctx.Request).Returns(request.Object);
    context.Setup(ctx => ctx.Response).Returns(response.Object);
    context.Setup(ctx => ctx.Session).Returns(session.Object);
    context.Setup(ctx => ctx.Server).Returns(server.Object);

    return context.Object;
}

但我的测试一直失败,我得到:

CanRenderEmployeeListSystem.ApplicationException : No Http Context, 
                                                          No Session to Get!

这是HttpContext.Current == null时要抛出的异常消息

我只需要 Session 对象“存在”,而不是存储在 Session 上的实际值。

你能告诉我我做错了什么吗?

谢谢。

【问题讨论】:

    标签: c# asp.net-mvc-3 nunit moq


    【解决方案1】:

    从长远来看,如果您为 SessionVar 类创建一个接口,您会更快乐。在运行时使用您当前的实现(通过依赖注入)。在测试期间插入模拟。无需模拟所有这些 Http 运行时依赖项。

    【讨论】:

    • 这就是我结束做的事情,不知何故感觉像是一种解决方法......但后来我发现其他人也在这样做,并且在你在这里发表评论之后:解决方法的感觉几乎消失了 :)
    【解决方案2】:

    您的 Session 属性中的 HttpContext.Current 不受您正在创建的模拟 HttpContextBase 的影响。也就是说,简单地创建一个本地 HttpContextBase 不会自动填充 HttpContext.Current。事实上 HttpContext 和 HttpContextBase 实际上并不相关。您必须使用 HttpContextWrapper 来统一它们。

    因此,您最好将 HttpContextWrapper 实现传递给您的类 SessionVar。在下面的代码中,我将您的方法和属性更改为实例级别,以便我们可以在构造函数中设置上下文。如果没有将上下文传递给构造函数,我们假定为 HttpContext.Current,但您也可以将模拟实例传递给您的测试。

    public class SessionVar
    {
        HttpContextWrapper m_httpContext;
    
        public SessionVar(HttpContextWrapper httpContext = null)
        {
            m_httpContext = httpContext ?? new HttpContextWrapper(HttpContext.Current);
        }
    
        /// <summary>
        /// Gets the session.
        /// </summary>
        private HttpSessionState Session
        {
            get
            {
                if (m_httpContext == null)
                    throw new ApplicationException("No Http Context, No Session to Get!");
    
                return m_httpContext.Session;
            }
        }
    
        public T Get<T>(string key)
        {
            return Session[key] == null ? default(T) : (T)Session[key];
        }
        ...
    }
    

    【讨论】:

    • 我认为这也是一个很好的解决方案,但我更喜欢@PatrickSteele 的解决方案,事实上这就是我最终实施的解决方案。感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 2011-05-21
    • 2019-09-27
    • 1970-01-01
    • 2018-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多