Lar*_*ard 5 c# asp.net-mvc caching unit-testing
我有一个服务层,其中包含多种方法。这些方法已实现缓存,如下所示:
string key = "GetCategories";
if (CacheHandler.IsCachingEnabled() && !CacheHandler.ContainsKey(key))
{
var categories = RequestHelper.MakeRequest("get_category_index")["categories"];
var converted = categories.ToObject<List<Category>>();
CacheHandler.InsertToCache(key,converted);
return converted;
}
return CacheHandler.GetCache(key) as List<Category>;
Run Code Online (Sandbox Code Playgroud)
现在,问题是我也想进行单元测试,如下所示:
[TestMethod]
public void GetCategories()
{
IContentService contentService = new ContentService();
var resp = contentService.GetCategories();
Assert.IsNotNull(resp,"Should not be null");
}
Run Code Online (Sandbox Code Playgroud)
问题是,在单元测试期间,HttpContext.Current
内部my CacheHandler
为空(显然)。
解决此问题的最简单方法是什么?
(请尽可能具体,因为我之前没有做过很多单元测试)
这尖叫着依赖注入。我认为主要的问题是,你访问CacheHandler
静态,所以在一个单元测试,您可以:
A)不能没有“测试”的测试服务CacheHandler
,以及
二)不能提供任何其他CacheHandler
的服务,例如嘲笑一个
如果您的情况可行,则我将重构或至少包装,CacheHandler
以便服务访问该实例。然后在单元测试中,您可以为服务提供“伪造”的东西CacheHandler
,该伪造者将无法访问HttpContext,并且还可以对测试本身进行很好的控制(例如,您可以测试在缓存项目时与何时缓存项目时发生的情况。它不在两个绝对独立的单元测试中)
对于模拟部分,我想最简单的方法是创建一个接口,然后使用一些专门为测试而设计的自动模拟 /代理生成框架,例如Rhino Mocks(但还有很多,只是我正在使用此接口并且非常高兴:))。另一种方法(较适合初学者,但在实际开发中更麻烦)将只是设计CacheHandler
(或其包装),以便您可以从中继承并自己重写行为。
最后,对于注入本身,我发现了一个方便的“模式”,该模式利用了C#默认方法参数和标准构造函数注入。服务构造函数如下所示:
public ContentService(ICacheHandler cacheHandler = null)
{
// Suppose I have a field of type ICacheHandler to store the handler
_cacheHandler = cacheHandler ?? new CacheHandler(...);
}
Run Code Online (Sandbox Code Playgroud)
因此,在应用程序本身中,我可以调用不带参数的构造函数(或者让框架构造服务,如果它是ASP.NET处理程序,WCF服务或其他某种类),并且在单元测试中,我可以提供实现上述内容的任何内容接口。
对于Rhino Mocks,它可能看起来像这样:
var mockCacheHandler = MockRepository.GenerateMock<ICacheHandler>();
// Here I can mock/stub methods and properties, set expectations etc...
var sut = new ContentService(mockCacheHandler);
Run Code Online (Sandbox Code Playgroud)