【问题标题】:How to Mock HttpContextBase correctly so my unit tests are working如何正确模拟 HttpContextBase 以便我的单元测试正常工作
【发布时间】:2014-05-28 03:34:17
【问题描述】:

给定以下函数:

public static void Write(HttpContextBase contextBase, IUnitOfWork unitOfWork, LogLevel level, string title, string message, params AdditionalProperty[] properties)
{
    // Some variables that are set for writing the logs.
    //      - client: When the HttpContext is null, 'N.A.' is used, otherwise the I.P. address of the requesting computer.
    //      - userIdentifier: When the HttpContext exists and a value is stored in the cookie, the value of the cookie, otherwise an empty guid.
    //      - requestIdentifier: When the context is existing and a request have been made on a controller, a unique value identifying this request, otherwise an empty guid.

    string client = (contextBase.ApplicationInstance == null || contextBase.ApplicationInstance.Context.CurrentHandler == null) ? "N.A." : HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
    string userIdentifier = (contextBase.ApplicationInstance != null && contextBase.ApplicationInstance.Context != null && contextBase.ApplicationInstance.Context.CurrentHandler != null && CookieManager.Exists("UserIdentifier")) ? CookieManager.Read("UserIdentifier", Guid.NewGuid().ToString().ToUpper()) : Guid.Empty.ToString();
    string requestIdentifier = (contextBase.ApplicationInstance != null && contextBase.ApplicationInstance.Context != null && contextBase.ApplicationInstance.Context.Cache != null && HttpContext.Current.Cache["RequestIdentifier"] != null) ? HttpContext.Current.Cache["RequestIdentifier"].ToString() : Guid.Empty.ToString();

    // Additional code for processing is done here.
}

我正在为工作单元使用 HttpContextBase 和接口,因为我知道它比单元测试更容易。

现在我正在使用 Moq 在我的单元测试中使用 Mocking 功能,我正在努力解决它。

让我们看看变量client:

string client = (contextBase.ApplicationInstance == null || contextBase.ApplicationInstance.Context.CurrentHandler == null) ? "N.A." : HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];

我想知道如何通过模拟必要的对象来设置我的单元测试。

这是我当前的单元测试:

var context = new Mock<HttpContextBase>();
var httpApplicationMock = new Mock<HttpApplication>();

httpApplicationMock.SetupGet(x => x.Context).Returns(context.Object); --> FAILS
context.SetupGet(c => c.ApplicationInstance).Returns(httpApplicationMock.Object);

httpApplicationMock 设置失败,因为 context.Object 不是有效参数,但我需要传入 HttpContext。

有人可以向我轻轻推动一下正确的方向吗?

【问题讨论】:

    标签: c# unit-testing mocking moq


    【解决方案1】:

    此行失败,因为 Context 返回 HttpContext 类型,而不是 HttpContextBase

    httpApplicationMock.SetupGet(x => x.Context).Returns(context.Object);
    

    context 创建为 Mock&lt;HttpContext&gt; 实例也无济于事,因为它是一个密封类,而 Moq 不能模拟密封类。

    您可以在接口后面隐藏有关 HttpContext 的实现细节。这是向您展示示例的博客文章:http://volaresystems.com/Blog/post/2010/08/19/Dont-mock-HttpContext

    【讨论】:

    • 这确实意味着我还需要重写我的“LogManager”,因为您希望我将接口传递给它(也许通过使用依赖注入)。对吗?
    • @Complexity 我没有看到您的 LogManager 类,但通过注入传递依赖项通常是个好主意。不过我不会称之为重写。
    • 好吧,我已经解决了这个问题并告诉你它是什么。在我的 LogManager 类中,我正在查看 HttpContext 和单元测试中不可用的东西。因此,我将一个参数传递给我的 logManager,而不是那个,它是一个具有 HttpContext 属性的接口。在我的 Web 应用程序中,我有一个接口的实现,其中所有属性都基于 HttpContext 填充,而在我的单元测试中,我确实有一个只返回字符串值的接口的模拟。你能向我确认这是正确的工作方式吗?
    • @Complexity 我也会这样做,但不能说它是否正确:)
    • 我明白了。一个问题仍然存在。我无法对具有 HttpContext 属性的类进行单元测试,以查看 if 语句是否正确,但这不是真正的问题。我认为这个案子已经结案。感谢您的宝贵帮助:-)
    【解决方案2】:

    经过一些进一步的测试,我意识到出了什么问题。

    首先,非常重要的是,我使用的是 MSTest。所以问题不依赖于在构造函数中创建的存储库,因为对于通过 MSTest 运行的每个测试,构造函数都会被执行。这样就消除了。

    经过进一步检查,我意识到,为了从 settingsrepository 中检索设置,我使用了一个实例化为 Singleton 的类,这就是问题所在。

    当我使用具有指定设置的单元测试运行我的第一个文件时,一切都很好,因为仍然需要创建设置。

    但是在我的第二个文件中,我使用了另一个设置,但是由于负责获取设置的管理器是单例,因此没有检索到新设置,而是使用了前一个设置。

    这导致了问题。

    无论如何,感谢那些试图帮助我解决这种情况的人。

    【讨论】:

      猜你喜欢
      • 2021-11-19
      • 1970-01-01
      • 1970-01-01
      • 2020-06-12
      • 2021-07-04
      • 1970-01-01
      • 2019-12-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多