【问题标题】:How do I mock/fake the session object in ASP.Net Web forms?如何模拟/伪造 ASP.Net Web 表单中的会话对象?
【发布时间】:2010-12-31 04:28:00
【问题描述】:

在创建单元测试时,有没有办法在 ASP.Net Web 表单中模拟/伪造会话对象?

我目前将用户详细信息存储在我的业务逻辑可以访问的会话变量中。

单独测试我的业务逻辑时,会话不可用。这似乎表明设计不好(尽管我不确定)。业务逻辑层应该首先访问会话变量吗?

如果是这样,那么我将如何将用户详细信息与假对象交换以进行测试?

【问题讨论】:

标签: asp.net session webforms tdd mocking


【解决方案1】:

您基本上可以使用 4 行代码来完成。虽然这并没有说明之前将会话移出业务逻辑层的评论,但如果您使用与会话高度耦合的遗留代码(我的场景),有时您可能需要这样做。

命名空间:

using System.Web;
using System.IO;
using System.Web.Hosting;
using System.Web.SessionState;

代码:

HttpWorkerRequest _wr = new SimpleWorkerRequest(
    "/dummyWorkerRequest", @"c:\inetpub\wwwroot\dummy",
    "default.aspx", null, new StringWriter());

HttpContext.Current = new HttpContext(_wr);

var sessionContainer = new HttpSessionStateContainer(
    "id", new SessionStateItemCollection(),
    new HttpStaticObjectsCollection(), 10, true,
    HttpCookieMode.AutoDetect, SessionStateMode.InProc, false);

SessionStateUtility.AddHttpSessionStateToContext(
    HttpContext.Current, sessionContainer);

然后您可以参考会话而不会收到 NullReferenceException 错误:

HttpContext.Current.Session.Add("mySessionKey", 1);

这是我从以下文章中编译的代码组合:

【讨论】:

  • 从单元测试类调用索引方法时出现 ViewEngine 异常。有没有相同的解决方案?
【解决方案2】:

在 ASP.NET 中,您不能创建 HttpSessionState 的测试替身,因为它是 sealed。是的,对于 ASP.NET 的原始设计者来说,这是一个糟糕的设计,但没有什么可做的。

这是 TDD 和其他 SOLID 实践者在很大程度上放弃 ASP.NET 转而支持 ASP.NET MVC 和其他更可测试的框架的众多原因之一。在 ASP.NET MVC 中,HTTP 会话由抽象的 HttpSessionStateBase 类建模。

您可以采用类似的方法,让您的对象在一个抽象会话上工作,然后当您在 ASP.NET 环境中运行时包装真正的 HttpSessionState 类。根据具体情况,您甚至可以重用 System.Web.Abstractions 中的类型,但如果不能,您可以定义自己的类型。

无论如何,您的业务逻辑是您的域模型,它应该独立于任何特定的运行时技术进行建模,所以我会说它不应该访问会话对象第一名。

如果您绝对需要对涉及 HttpSessionState 的单元 tets 使用测试替身,这仍然可以使用某些侵入性动态模拟,例如 TypeMockMoles,尽管这些也有很多缺点(请参阅 this comparison of dynamic mocks )。

【讨论】:

    【解决方案3】:

    您的直觉是正确的——您不应该从业务逻辑中访问 ASP.NET 框架的各个部分。这将包括会话。

    要回答您的第一个问题,您可以使用 Typemock Isolator 之类的产品来模拟静态类,但如果您重构代码以将 Session 的访问封装在接口中(即, IHttpSession。)然后您可以模拟 IHttpSession。

    【讨论】:

      【解决方案4】:

      在 Asp.Net webforms 中,您无法逃避这样一个事实,即框架进入您的代码来自 aspx 页面。我同意你的业务层不应该直接接触 asp.net 特定的组件,但你必须有一个模型的存储容器,并且 asp.net 中的会话是一个很好的区域。因此,一种可能的方法是创建 ISessionManager 以便在业务层内部进行交互。然后,使用 HttpSessionState 实现具体类型……顺便说一句,一个好的技巧是使用 HttpContext.Current.Session 从 HttpSessionState 中实现访问器/获取器。 您的下一个挑战是如何将它们连接在一起。

      【讨论】:

        【解决方案5】:

        一种方法是将 lambda 表达式传递给您的代码,该表达式将字符串(或其他对象)作为输入,并使用它来设置 Session 对象或测试容器。

        但是,正如其他人所说,将 Session 对象的访问权限移出 BLL 是个好主意。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-10-08
          • 1970-01-01
          • 2012-07-02
          • 1970-01-01
          • 2010-09-10
          • 2012-06-28
          相关资源
          最近更新 更多