开发者

Unit testing an MVC action method with a Cache dependency?

开发者 https://www.devze.com 2022-12-23 03:12 出处:网络
I’m relatively new to testing and MVC and came across a sticking point today.I’m attempting to test an action method that has开发者_Python百科 a dependency on HttpContext.Current.Cache and wanted to

I’m relatively new to testing and MVC and came across a sticking point today. I’m attempting to test an action method that has开发者_Python百科 a dependency on HttpContext.Current.Cache and wanted to know the best practice for achieving the “low coupling” to allow for easy testing. Here's what I've got so far...

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

I then access it like such... I'm using Castle for my 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();
   ...

Then in my unit tests I am able to mock up ICacheHandler.

Would this be considered a 'best practice' and does anyone have any suggestions for other approaches?


The recommended approach is to stub HttpContextBase. Its documentation states

When you perform unit testing, you typically use a derived class to implement members with customized behavior that fulfills the scenario you are testing.

This is mostly covered for 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;


You are hiding a specific, hard-to-test API (HttpContext.Current) behind and interface and using Constructor Injection to inject the dependency into the consumer. That's more or less textbook DI (I would add Guard Clauses in the constructor, though).

If you create a new ASP.NET MVC project in Visual Studio, you will see that in the AccountController.cs file, a very similar thing is being done to hide the MembershipProvider.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号