如何在ASP.Net Web Forms中模拟/伪造会话对象?

17

在创建单元测试时,ASP.Net Web Forms是否有一种方法来模拟/伪造会话对象?

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

在隔离测试我的业务逻辑时,会话不可用。这似乎表明设计存在问题(尽管我不确定)。首先,业务逻辑层是否应该访问会话变量?

如果是这样,那么我应该如何用一个虚假对象交换用户详细信息进行测试?


还可以查看我在这个问题上的回答 - https://dev59.com/YV7Va4cB1Zd3GeqPHz1b#8487847 - Merlyn Morgan-Graham
5个回答

29
你可以用基本的4行代码来完成它。虽然这并没有解决将session移出业务逻辑层的问题,但如果你正在使用与session紧密耦合的遗留代码(我的情况),有时候你仍然需要这样做。
命名空间:
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异常。是否有任何解决方案? - Manish Parmar

9
在ASP.NET中,你无法创建HttpSessionState的Test Double,因为它是sealed。是的,这是ASP.NET原始设计者不好的设计,但是没有太多可以做的事情。
这是TDD'ers和其他SOLID实践者大量放弃ASP.NET转而使用ASP.NET MVC和其他更可测试的框架的许多原因之一。在ASP.NET MVC中,HTTP会话由抽象的HttpSessionStateBase类建模。
您可以采取类似的方法,让您的对象在抽象会话上工作,然后在运行在ASP.NET环境中时包装真正的HttpSessionState类。根据情况,您甚至可以重用System.Web.Abstractions中的类型,但如果不能,则可以定义自己的类型。
在任何情况下,您的业务逻辑是您的域模型,应独立于任何特定的运行时技术进行建模,因此我认为它不应首先访问会话对象。
如果您绝对需要使用Test Doubles来进行涉及HttpSessionState的单元测试,则仍然可以使用某些侵入式动态模拟,例如TypeMockMoles,尽管这些也带有很多缺点(请参见这个动态模拟的比较)。

1

你的直觉是正确的——你不应该从业务逻辑中访问ASP.NET框架的部分,包括Session。

回答你的第一个问题,你可以使用像Typemock Isolator这样的产品来模拟静态类,但如果你重构代码以在接口(即IHttpSession)中包装对Session的访问,效果会更好。然后你就可以模拟IHttpSession了。


1
在Asp.Net webforms中,你无法逃避框架从aspx页面进入你的代码的事实。我同意你的业务层不应直接触及asp.net特定组件,但你必须拥有一个模型存储容器,而在asp.net中,session是一个很好的选择。因此,一种可能的方法是创建ISessionManager以便在业务层内部进行交互。然后,通过使用HttpSessionState来实现具体类型...顺便说一句,一个好的技巧是使用HttpContext.Current.Session来实现从HttpSessionState获取访问器/获取器。
你下一个挑战将是如何将所有这些东西连接在一起。

0

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

然而,正如其他人所说,最好将访问 Session 对象的操作从 BLL 中移出。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接