我有一个Web服务,我正在尝试进行单元测试 . 在服务中,它从 HttpContext
中提取了几个值,如下所示:
m_password = (string)HttpContext.Current.Session["CustomerId"];
m_userID = (string)HttpContext.Current.Session["CustomerUrl"];
在单元测试中,我使用简单的工作者请求创建上下文,如下所示:
SimpleWorkerRequest request = new SimpleWorkerRequest("", "", "", null, new StringWriter());
HttpContext context = new HttpContext(request);
HttpContext.Current = context;
但是,每当我尝试设置 HttpContext.Current.Session
的值时
HttpContext.Current.Session["CustomerId"] = "customer1";
HttpContext.Current.Session["CustomerUrl"] = "customer1Url";
我得到空引用异常,说 HttpContext.Current.Session
为null .
有没有办法在单元测试中初始化当前会话?
13 回答
你可以试试FakeHttpContext:
试试这个:
并添加课程:
这将允许您使用会话和缓存进行测试 .
如果您正在使用MVC框架,这应该可行 . 我使用了Milox's FakeHttpContext并添加了一些额外的代码行 . 这个想法来自这篇文章:
http://codepaste.net/p269t8
这似乎适用于MVC 5.我没有在早期版本的MVC中尝试过这种方法 .
永远不要嘲笑......解决方案非常简单 . 为什么假装像
HttpContext
这样美丽的创作呢?推下 Session ! (这条线足以让我们大多数人理解,但在下面详细解释)
(string)HttpContext.Current.Session["CustomerId"];
是我们现在访问它的方式 . 将此更改为从test调用时,_customObject使用备用存储(DB或 Cloud 键值[http://www.kvstore.io/])
但是当从真实应用程序调用时,
_customObject
使用Session
.怎么做的?嗯...依赖注入!
因此,测试可以设置会话(地下),然后调用应用程序方法,就好像它对会话一无所知 . 然后测试秘密检查应用程序代码是否正确更新了会话 . 或者,如果应用程序的行为基于测试设置的会话值 .
实际上,即使我说:"never mock",我们最终还是嘲笑了 . 因为我们忍不住溜到下一个规则,"mock where it hurts the least!" . 嘲笑巨大的
HttpContext
或嘲笑一个微小的会话,这会伤害最少?不要问我这些规则来自何处 . 我们只说常识 . 这是一篇关于不嘲笑的有趣读物as unit test can kills us我们不得不使用
HttpContextManager
模拟HttpContext
并在我们的应用程序中调用工厂以及单元测试然后,您将使用
HttpContextManager.Current
替换对HttpContext.Current
的任何调用,并且可以访问相同的方法 . 然后,当您进行测试时,您还可以访问HttpContextManager
并模拟您的期望这是使用Moq的示例:
然后在你的单元测试中使用它,我在我的Test Init方法中调用它
然后,您可以在上面的方法中添加您希望Web服务可用的Session的预期结果 .
Milox solution比接受的恕我直言,但I had some problems with this implementation when handling urls with querystring好 .
我做了一些更改,使其适用于任何网址,并避免反射 .
我刚才有点蠢蠢欲动 .
Unit Testing HttpContext.Current.Session in MVC3 .NET
希望能帮助到你 .
我找到了以下用于在HttpContext中指定用户的简单解决方案:https://forums.asp.net/post/5828182.aspx
你可以通过这样创建一个新的
HttpContext
来"fake it":http://www.necronet.org/archive/2010/07/28/unit-testing-code-that-uses-httpcontext-current-session.aspx
我已经把这些代码放在一个静态帮助器类上,如下所示:
或者不是使用反射来构造新的
HttpSessionState
实例,只需将HttpSessionStateContainer
附加到HttpContext
(根据Brent M. Spell的评论):然后你可以在你的单元测试中调用它,如:
与我合作的答案是@Anthony写的,但你必须添加另一行
所以你可以用这个:
在asp.net Core / MVC 6 rc2中你可以设置
HttpContext
rc 1是
https://stackoverflow.com/a/34022964/516748
考虑使用
Moq
我正在寻找比上面提到的选项更少侵入性的东西 . 最后我提出了一个俗气的解决方案,但它可能会让一些人移动得更快一点 .
首先,我创建了一个TestSession类:
然后我在控制器的构造函数中添加了一个可选参数 . 如果参数存在,请将其用于会话操作 . 否则,使用HttpContext.Session:
现在我可以将TestSession注入控制器:
答案 @Ro Hit 给了我很多帮助,但是我错过了用户凭据,因为我不得不伪造用户进行身份验证单元测试 . 因此,让我描述一下我是如何解决它的 .
根据this,如果添加方法
然后追加
在您完成的
TestSetup
方法的最后一行,添加了用户凭据并准备用于身份验证测试 .我还注意到您可能需要HttpContext中的其他部分,例如
.MapPath()
方法 . 有一个FakeHttpContext可用,它是described here,可以通过NuGet安装 .