Принцип єдиної відповідальності - ваш найкращий друг тут.
Перш за все, перемістіть AllFromCache () у клас сховища та назвіть його GetAll (). Те, що воно витягується з кеша, є деталлю реалізації репозиторію і його не повинно знати кодовий код.
Це робить тестування вашого класу фільтрації приємним та простим. Це вже не хвилює, звідки ви його отримуєте.
По-друге, загортайте клас, який отримує дані з бази даних (або деінде), в обгортку кешування.
AOP - хороша техніка для цього. Це одна з небагатьох речей, в якій це дуже добре.
Використовуючи такі інструменти, як PostSharp , ви можете налаштувати його так, що будь-який метод, позначений вибраним атрибутом, буде кешований. Однак, якщо це єдине, що ви кешуєте, вам не потрібно йти так далеко, щоб мати рамку AOP. Просто є сховище та кешируюча обгортка, які використовують той самий інтерфейс і вводять його в клас виклику.
напр.
public class ProductManager
{
private IProductRepository ProductRepository { get; set; }
public ProductManager
{
ProductRepository = productRepository;
}
Product FetchById(guid id) { ... }
IList<Product> FilterByPropertry(int property) { ... }
}
public interface IProductRepository
{
IList<Product> GetAll();
}
public class SqlProductRepository : IProductRepository
{
public IList<Product> GetAll()
{
// DB Connection, fetch
}
}
public class CachedProductRepository : IProductRepository
{
private IProductRepository ProductRepository { get; set; }
public CachedProductRepository (IProductRepository productRepository)
{
ProductRepository = productRepository;
}
public IList<Product> GetAll()
{
// Check cache, if exists then return,
// if not then call GetAll() on inner repository
}
}
Подивіться, як ви видалили з ProductManager знання про реалізацію сховища? Дивіться також, як ви дотримувались принципу єдиної відповідальності, маючи клас, який обробляє вилучення даних, клас, який обробляє пошук даних, і клас, який обробляє кешування?
Тепер ви можете інстанціювати ProductManager одним із цих сховищ і отримати кешування ... чи ні. Це неймовірно корисно пізніше, коли ви отримаєте заплутану помилку, яку ви підозрюєте, є результатом кешу.
productManager = new ProductManager(
new SqlProductRepository()
);
productManager = new ProductManager(
new CachedProductRepository(new SqlProductRepository())
);
(Якщо ви використовуєте контейнер IOC, ще краще. Потрібно зрозуміти, як адаптуватися.)
І, у ваших тестах ProductManager
IProductRepository repo = MockRepository.GenerateStrictMock<IProductRepository>();
Зовсім не потрібно тестувати кеш.
Тепер виникає питання: чи варто перевірити CachedProductRepository? Я пропоную ні. Кеш досить невизначений. Рамка робить з нею речі, які ви не контролюєте. Наприклад, просто виймаючи з нього речі, наприклад, коли він занадто заповнюється. Ви закінчите тести, які провалюються один раз у синьому місяці, і ви ніколи не зрозумієте чому.
Зробивши запропоновані вище зміни, насправді не так багато логіки для перевірки. Дійсно важливий тест, метод фільтрації, буде там і повністю абстрагується від деталей GetAll (). GetAll () просто ... отримує все. Звідкись.