Модульное тестирование метода действия MVC с зависимостью Cache? - PullRequest
2 голосов
/ 12 марта 2010

Я относительно новичок в тестировании и 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 ]

2 голосов
/ 12 марта 2010

Рекомендуется использовать заглушку HttpContextBase . В его документации говорится

Когда вы выполняете модульное тестирование, вы обычно используют производный класс для внедрить членов с настроенными поведение, которое соответствует сценарию вы тестируете.

В основном это относится к TypeMock здесь .

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 голос
/ 12 марта 2010

Вы скрываете определенный, трудно тестируемый API (HttpContext.Current) за интерфейсом и используете Конструкторское внедрение для внедрения зависимости в потребителя. Это более или менее учебник DI (я бы добавил в конструктор статьи Guard Guarduses).

Если вы создадите новый проект ASP.NET MVC в Visual Studio, вы увидите, что в файле AccountController.cs очень похожая вещь делается для скрытия MembershipProvider.

...