单元测试具有Cache依赖性的MVC操作方法?

时间:2010-03-11 21:16:29

标签: c# asp.net-mvc caching dependency-injection mocking

我对测试和MVC相对较新,今天遇到了一个棘手的问题。我正在尝试测试一个依赖于HttpContext.Current.Cache的动作方法,并想知道实现“低耦合”以便于测试的最佳实践。这是我到目前为止所得到的......

 public class CacheHandler : ICacheHandler
 {
    public IList<Section3ListItem> StateList
    {
        get { return (List<Section3ListItem>)HttpContext.Current.Cache["StateList"]; }
        set { HttpContext.Current.Cache["StateList"] = value; }
    }
 ...

然后我就这样访问了......我正在使用Castle作为我的IoC。

public class ProfileController : ControllerBase
{
    private readonly ISection3Repository _repository;
    private readonly ICacheHandler _cache;

    public ProfileController(ISection3Repository repository, ICacheHandler cacheHandler)
    {
        _repository = repository;
        _cache = cacheHandler;
    }

    [UserIdFilter]
    public ActionResult PersonalInfo(Guid userId)
    {
        if (_cache.StateList == null)
            _cache.StateList = _repository.GetLookupValues((int)ELookupKey.States).ToList();
   ...

然后在我的单元测试中,我可以模拟ICacheHandler。

这会被视为“最佳做法”,是否有人对其他方法有任何建议?

2 个答案:

答案 0 :(得分:2)

推荐的方法是存根HttpContextBase。其文件说明

  

当你进行单元测试时,你   通常使用派生类   实现定制的成员   满足场景的行为   你正在测试。

这主要适用于TypeMock here

var httpContext = MockRepository.GenerateStub<HttpContextBase>();
httpContext.Stub(x=>x.Cache).Return(yourFakeCacheHere);

var controllerContext = new ControllerContext(httpContext, ....);

var controller = new HomeController();
controller.ControllerContext = controllerContext;

答案 1 :(得分:1)

您隐藏了一个特定的,难以测试的API (HttpContext.Current),并且使用构造函数注入将依赖项注入到使用者中。这或多或少是教科书DI (我会在构造函数中添加Guard子句)。

如果在Visual Studio中创建一个新的ASP.NET MVC项目,您将看到在AccountController.cs文件中,正在执行一项非常类似的操作来隐藏MembershipProvider。