2012-04-30 4 views
7

Я пишу какой-то единичный тест, и мне интересно, полезно ли издеваться над Cache, и если да, то как?Mocking System.Web.Caching.Cache - Mock или проверка на null?

В настоящее время в моих тестах я насмешливый вне HttpContextBase и окружив его обычаем HttpContextFactory:

var mockedHttpContextBase = new Mock<HttpContextBase>(); 

IHttpContextFactory httpContextFactory = new HttpContextFactory 
{ 
    Current = mockedHttpContextBase.Object 
}; 

и когда мой код потребляет IHttpContextFactory проверить, если кэш является недействительным, прежде чем делать что-либо с ним.

var cache = _httpContextFactory.Current.Cache; 

Func<SomeReturnType> doSomeWork =() => _foo.someMethodIExecute(param1,param2); 

return cache != null ? cache.GetOrStore("doSomeWorkCacheKey",doSomeWork, 900) 
        : doSomeWork.Invoke(); 

ли право проверять кэш будучи пустой, как это каждый раз, когда я использую его, или вы бы издеваться кэша также в тесте, так что это не нуль при выполнении модульных тестов?

ответ

3

Если ваш код предполагает кэш может быть null и выполняет проверку перед доступом к ней (как это происходит сейчас), вам нужно иметь два модульные тесты для каждого доступа кэша:

  • кэша существует и элемент хранение и извлечение (проверка GetOrStore вызова)
  • кэш является недействительным, и вы просто утверждать делегат вызов

Если это общий шаблон (нулевая проверка), вместо того, чтобы иметь два теста каждый раз, когда требуется зависимость от кеша, я предлагаю обернуть его в Null Object Pattern и протестировать его один раз и позже, просто используя NOP в качестве зависимости, которую можно издеваться.

Edit: кэш «издевается» пример

var cache = new Cache(); 
// Add takes more parameters; fill whatever is necessary to make it work 
cache.Add("doSomeWorkCacheKey", doSomeWork, ...); 
var mockedHttpContextBase = new Mock<HttpContextBase>(); 
// tell your mock to return pre-configured cache 
mockedHttpContextBase.Setup(m => m.Cache).Returns(cache); 

IHttpContextFactory httpContextFactory = new HttpContextFactory 
{ 
    Current = mockedHttpContextBase.Object 
}; 
+0

Спасибо Джимми. Что касается пункта 1, как бы вы могли написать тест, который зависит от существующего кеша? Как бы вы издевались над кешем в этом случае, чтобы выполнить тест? –

+0

@JamieDixon: вы не можете высмеять 'Cache', поскольку он запечатан; вам придется предварительно сконфигурировать его с помощью реальной реализации «Cache» и сделать ваш «HttpContextBase» макетным, чтобы запросить предварительно сконфигурированный кеш. Я добавил пример на свой пост. –

+0

Еще раз спасибо Джимми. Я ценю ваше время и помощь. Я добавил ответ сам после того, как сделал больше поиска. Кажется, что использование «HttpRuntime.Cache» более уместно, так как оно будет создавать все, что ему нужно, чтобы работать там, где «System.Web.Caching.Cache» будет бросать «NullReferenceExeption», если все не настроено. –

13

После небольшого поиска, кажется, что я могу использовать HttpRuntime.Cache вместо System.Web.Caching.Cache при написании моих модульных тестов.

Такой, что:

var mockedHttpContextBase = new Mock<HttpContextBase>(); mockedHttpContextBase.Setup(m => m.Cache).Returns(HttpRuntime.Cache);

Кэш никогда не должен быть null (это было бы соответствующее исключение, если оно было), так что я могу удалить пустую ссылку проверки из моего кода.

+0

Хороший ход обойти unMoq'able запечатанный System.Web.Caching.Cache с HttpRuntime.Cache – BozoJoe

+0

Это не сработало для меня, потому что мои тесты асинхронны. Таким образом, 'HttpRuntime.Cache' разделяет состояние, а не на тест. Он работает при выполнении тестов по отдельности. –

+0

Чтобы быть ясным - вы не создаете кеш в этом случае. Просто добавьте свои элементы в HttpRuntime.Cache, прежде чем использовать измененную версию. 'HttpRuntime.Cache.Add (cacheKey, sampleUser, null, DateTime.Now.AddHours (2), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null); var context = new Mock (); context.Setup (x => x.Cache) .Returns (HttpRuntime.Cache); ' – Lavamantis

Смежные вопросы