C# 中的单元测试 HttpContext.Current.Cache 或其他服务器端方法?
为使用 的类创建单元测试时HttpContext.Current.Cache
类,使用 NUnit 时出现错误。 该功能是基本的 - 检查一个项目是否在缓存中,如果没有,则创建它并将其放入:
if (HttpContext.Current.Cache["Some_Key"] == null) {
myObject = new Object();
HttpContext.Current.Cache.Insert("Some_Key", myObject);
}
else {
myObject = HttpContext.Current.Cache.Get("Some_Key");
}
从单元测试调用此功能时,遇到第一个 NullReferenceException
时会失败。代码>缓存行。 在 Java 中,我会使用 Cactus 来测试服务器端代码。 是否有类似的工具可以用于 C# 代码? 这个问题提到了模拟框架- 这是我测试这些方法的唯一方法吗? 有没有类似的工具来运行 C# 测试?
另外,我不检查 Cache
是否为空,因为我不想专门为单元测试编写代码,并假设它在服务器上运行时始终有效。 这是有效的,还是应该在缓存周围添加空检查?
When creating a unit test for a class that uses the HttpContext.Current.Cache
class, I get an error when using NUnit. The functionality is basic - check if an item is in the cache, and if not, create it and put it in:
if (HttpContext.Current.Cache["Some_Key"] == null) {
myObject = new Object();
HttpContext.Current.Cache.Insert("Some_Key", myObject);
}
else {
myObject = HttpContext.Current.Cache.Get("Some_Key");
}
When calling this from a unit test, it fails with at NullReferenceException
when encountering the first Cache
line. In Java, I would use Cactus to test server-side code. Is there a similar tool I can use for C# code? This SO question mentions mock frameworks - is this the only way I can test these methods? Is there a similar tool to run tests for C#?
Also, I don't check if the Cache
is null as I don't want to write code specifically for the unit test and assume it will always be valid when running on a server. Is this valid, or should I add null checks around the cache?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(14)
做到这一点的方法是避免直接使用 HttpContext 或其他类似的类,并用模拟替代它们。 毕竟,您并不是要测试 HttpContext 是否正常运行(这是微软的工作),您只是想测试这些方法是否在应该调用时被调用。
步骤(如果您只是想了解该技术而不需要深入研究大量博客):
创建一个接口来描述您想要在缓存中使用的方法(可能是 GetItem、SetItem、ExpireItem 等)。 称其为 ICache 或任何您喜欢的名称
创建一个实现该接口的类,并将方法传递给真正的 HttpContext
Create一个实现相同接口的类,其作用就像一个模拟缓存。 如果您关心保存对象,它可以使用字典或其他东西
更改您的原始代码,以便它根本不使用 HttpContext,而只使用 ICache。 然后,代码需要获取 ICache 的实例 - 您可以在类构造函数中传递一个实例(这就是依赖注入的真正含义),或者将其粘贴到某个全局变量中。
在您的生产应用程序中,将 ICache 设置为真正的 HttpContext-Backed-Cache,并在单元测试中,将 ICache 设置为模拟缓存。
利润!
The way to do this is to avoid direct use of the HttpContext or other similar classes, and substitute them with mocks. After all, you're not trying to test that the HttpContext functions properly (that's microsoft's job), you're just trying to test that the methods got called when they should have.
Steps (In case you just want to know the technique without digging through loads of blogs):
Create an interface which describes the methods you want to use in your caching (probably things like GetItem, SetItem, ExpireItem). Call it ICache or whatever you like
Create a class which implements that interface, and passes methods through to the real HttpContext
Create a class which implements the same interface, and just acts like a mock cache. It can use a Dictionary or something if you care about saving objects
Change your original code so it doesn't use the HttpContext at all, and instead only ever uses an ICache. The code will then need to get an instance of the ICache - you can either pass an instance in your classes constructor (this is all that dependency injection really is), or stick it in some global variable.
In your production app, set the ICache to be your real HttpContext-Backed-Cache, and in your unit tests, set the ICache to be the mock cache.
Profit!
我同意其他人的观点,使用界面将是最好的选择,但有时改变现有系统是不可行的。 这是我刚刚从我的一个项目中混合在一起的一些代码,应该可以为您提供所需的结果。 这是离漂亮或伟大的解决方案最远的事情,但如果你真的无法改变你的代码,那么它应该可以完成工作。
I agree with the others that using an interface would be the best option but sometimes it’s just not feasible to change an existing system around. Here’s some code that I just mashed together from one of my projects that should give you the results you’re looking for. It’s the farthest thing from pretty or a great solution but if you really can’t change your code around then it should get the job done.
如果您使用的是 .NET 3.5,则可以在应用程序中使用 System.Web.Abstractions。
Justin Etheredge 有一篇很棒的 帖子 关于如何模拟 HttpContext(其中包含缓存类)。
在 Justin 的示例中,我使用 HttpContextFactory.GetHttpContext 将 HttpContextBase 传递到我的控制器。 当模拟它们时,我只是构建一个模拟来调用缓存对象。
If you're using .NET 3.5, you can use System.Web.Abstractions in your application.
Justin Etheredge has a great post on how to mock HttpContext (which contains the cache class).
From Justin's example, I pass an HttpContextBase to my controllers using the HttpContextFactory.GetHttpContext. When mocking them, I just build a Mock to make calls to the cache object.
有一种更新的方法可以帮助专门处理单元测试中的缓存。
我建议使用 Microsoft 的新 MemoryCache.Default 方法。 您将需要使用 .NET Framework 4.0 或更高版本,并包含对 System.Runtime.Caching 的引用。
请参阅此处的文章 --> http://msdn.microsoft.com/en- us/library/dd997357(v=vs.100).aspx
MemoryCache.Default 适用于 Web 和非 Web 应用程序。 因此,我们的想法是更新您的 web 应用程序以删除对 HttpContext.Current.Cache 的引用,并将其替换为对 MemoryCache.Default 的引用。 稍后,当您运行决定对这些相同的方法进行单元测试时,缓存对象仍然可用并且不会为空。 (因为它不依赖于 HttpContext。)
这样您甚至不一定需要模拟缓存组件。
There is a newer approach to help deal specifically with Cache in unit tests.
I would recommend using Microsoft's new MemoryCache.Default approach. You will need to use .NET Framework 4.0 or later and include a reference to System.Runtime.Caching.
See article here --> http://msdn.microsoft.com/en-us/library/dd997357(v=vs.100).aspx
MemoryCache.Default works for both web and non-web applications. So the idea is you update your webapp to remove references to HttpContext.Current.Cache and replace them with references to MemoryCache.Default. Later, when you run decide to Unit Test these same methods, the cache object is still available and won't be null. (Because it is not reliant on an HttpContext.)
This way you don't even necessarily need to mock the cache component.
普遍的共识似乎是,在单元测试中驱动任何与 HttpContext 相关的东西都是一场噩梦,如果可能的话应该避免。
我认为您在嘲笑方面走在正确的道路上。 我喜欢 RhinoMocks (http://ayende.com/projects/rhino-mocks.aspx)。
我也读过一些关于 MoQ 的好文章 (http://code.google.com/p/moq ),虽然我还没有尝试过。
如果您确实想用 C# 编写可单元测试的 Web UI,人们似乎正在使用 MVC 框架 (http://www.asp.net/mvc)而不是 WebForms...
General consensus seems to be that driving anything HttpContext related from within a unit test is a total nightmare, and should be avoided if possible.
I think you're on the right path regarding mocking. I like RhinoMocks (http://ayende.com/projects/rhino-mocks.aspx).
I've read some good things about MoQ too (http://code.google.com/p/moq), although I've not tried it yet.
If you really want to write unit testable web UIs in C#, the way people seem to be heading is to use the MVC framework (http://www.asp.net/mvc) rather than WebForms...
您可以在 System.Web.Abstractions.dll 中使用 HttpContextBase 类。 它是.NET 3.5 中的一个新的 dll。
您可以在下面的链接中找到如何使用的示例。
http://vkreynin.wordpress.com/2009/03/23/stub -htttpcontext/
You can use HttpContextBase class in System.Web.Abstractions.dll. It's a new dll in .NET 3.5.
You can find an example how to use in the link below.
http://vkreynin.wordpress.com/2009/03/23/stub-htttpcontext/
这可能是你的想法...... Phil Haack 在 Rhino 模拟的帮助下展示了如何在 asp mvc 中模拟 httpcontext,但我想它可以应用于 webforms。
点击!!
希望这会有所帮助。
This maybe up your street ... Phil Haack shows off, with the help of Rhino mocks, how to mock httpcontext in asp mvc but I'd imagine can be applied to webforms.
Clicky!!
Hope this helps.
如果您不关心测试缓存,您可以执行以下操作:
您也可以像下面这样起订量
if you dont care about testing cache you can do below:
Also you can moq like below
所有这些编程问题都需要基于接口的编程模型,在该模型中您需要实现两次接口。 一份用于真实代码,一份用于模型。
实例化是下一个问题。 有几种设计模式可以用于此目的。 例如,请参见著名的 GangOfFour 创建模式 (GOF) 或依赖注入模式。
ASP.Net MVC 实际上使用了这种基于接口的方法,因此更适合单元测试。
All of these programming questions ask for an interface based programming model, in which you implement the interface twice. One for the real code and one for the mockup.
Instantiation is then the next issue. There are several design patterns that can be used for that. See for example the famous GangOfFour Creational patterns (GOF) or the Dependency Injection patterns.
ASP.Net MVC is in fact using this interface-based approach and is therefore much more suitable for unit testing.
正如大家在这里所说的,HTTPContext有问题,目前 Typemock 是唯一可以直接伪造它而无需任何操作的框架包装器或抽象。
As everyone said here, there's a problem with HTTPContext, currently Typemock is the only framework that can fake it directly without any wrappers or abstractions.
缓存对象很难模拟,因为它是 .NET 框架的密封区域。 我通常通过构建一个接受缓存管理器对象的缓存包装器类来解决这个问题。 为了进行测试,我使用了模拟缓存管理器; 对于生产,我使用实际访问 HttpRuntime.Cache 的缓存管理器。
基本上,我自己抽象出缓存。
The cache object is difficult to mock because it's a sealed area of the .NET framework. I typically get around this by building a cache wrapper class that accepts a cache manager object. For testing, I use a mock cache manager; for production I use a cache manager that actually accesses HttpRuntime.Cache.
Basically, I abstract away the cache myself.
使用 MVC 3 和 MOQ 的示例:
我的控制器方法具有以下行:
因此,任何单元测试都会失败,因为我没有设置 HttpContext.Cache。
在我的单元测试中,我的安排如下:
An example for those using MVC 3 and MOQ:
My controller method has the following line:
As such, any unit test will fail as I'm not setting up HttpContext.Cache.
In my unit test, I arrange as follows:
可以尝试...
Could try...