Подтвердить что ты не робот

Как вы издеваетесь над кеширующим объектом в asp.net mvc?

Как мне высмеять объект кеширования в объекте ControllerContext для моих модульных тестов? Я попытался создать класс-оболочку, как показано ниже (поскольку объект кэша является закрытым классом) без везения.

var mockControllerContext = new Mock<ControllerContext>(); 
var mockhttpContext = new Mock<HttpContextBase>();            

mockhttpContext.SetupGet(o => o.Cache).Returns(
         new CacheWrapper(mockControllerContext.Object.HttpContext.Cache));

mockControllerContext.SetupGet(
                          o => o.HttpContext).Returns(mockhttpContext.Object);
this.tennisMatchupController.ControllerContext = mockControllerContext.Object; 
4b9b3361

Ответ 1

EDIT. Я нашел более простой способ сделать это, по крайней мере, когда вы тестируете пустой кеш. Используйте HttpRunTime.Cache как возвращаемое значение для вашего ожидания по свойству Cache HttpContext. Для более сложных сценариев использование обертки и издевательств все равно может быть лучшим способом ее обработки - например, если вам нужно проверить исключения из кеша.

var httpContext = MockRepository.GenerateMock<HttpContextBase>();
httpContext.Expect( h => h.Cache ).Return( HttpRunTime.Cache ).Repeat.Any()

Оригинал

Класс-оболочка - это путь, но я думаю, что вы применяете его не в том месте. Я бы дал моему контроллеру свойство CacheWrapper, а затем создал конструктор, который позволяет мне передать экземпляр CacheWrapper, для которого это свойство можно установить. По умолчанию контроллер создает CacheWrapper с использованием HttpContext.Current.Cache. В тестовом коде создайте mock CacheWrapper для перехода в конструктор контроллера. Таким образом вам вообще не нужно создавать макетный объект Cache - это сложно, потому что это закрытый класс.

В качестве альтернативы вы можете просто создать экземпляр класса Cache и вернуть его, поскольку для него существует публичный конструктор. Однако использование макета имеет то преимущество, что вы можете проверить, что кэш используется через ожидания, поэтому я, вероятно, поеду с оберткой.

public class CacheWrapper
{
  private Cache Cache { get; set; }

  public CacheWrapper()
  {
     this.Cache = HttpContext.Current.Cache;
  }

  public virtual Object Add( string key,
                             Object value,
                             CacheDependency dependencies,
                             DateTime absoluteExpiration,
                             TimeSpan slidingExpiration,
                             CacheItemPriority priority,
                             CacheItemRemovedCallback onRemoveCallback )
  {
     this.Cache.Add( key,
                     value,
                     dependencies,
                     absoluteExpiration,
                     slidingExpiration,
                     priority,
                     onRemoveCallback );
  }

  ...wrap other methods...
}


public class BaseController : Controller
{
    private CacheWrapper { get; set; }

    public BaseController() : this(null) { }

    public BaseController( CacheWrapper cache )
    {
        this.CacheWrapper = cache ?? new CacheWrapper();
    }
}

[TestMethod]
public void CacheTest()
{
   var wrapper = MockRepository.GenerateMock<CacheWrapper>();

   wrapper.Expect( o => o.Add( ... ) ).Return( ... );

   var controller = new BaseController( wrapper );

   var result = controller.MyAction() as ViewResult;

   Assert.AreEqual( ... );

   wrapper.VerifyAllExpectations();
}

Ответ 2

Я бы рекомендовал использовать новый подход MemoryCache.Default Microsoft. Вам понадобится использовать .NET Framework 4.0 или новее и включить ссылку на System.Runtime.Caching.

См. статью здесь → http://msdn.microsoft.com/en-us/library/dd997357(v=vs.100).aspx

MemoryCache.Default работает как для веб-приложений, так и для не-веб-приложений. Итак, идея заключается в том, что вы обновляете свой webapp, чтобы удалить ссылки на HttpContext.Current.Cache и заменить их ссылками на MemoryCache.Default. Позже, когда вы решите использовать Unit Test эти же методы, объект кеша все еще доступен и не будет пустым. (Потому что он не зависит от HttpContext.)

Таким образом, вам даже необязательно нужно издеваться над компонентом кэша.

Ответ 3

HttpContext.Current = new HttpContext(new HttpRequest(null, "http://tempuri.org", null), new HttpResponse(null));

Ответ 4

Вы можете использовать Typemock Isolator, он подделывает закрытые классы из коробки, поэтому вам не нужны эти обертки.