该单一职责原则在这里你最好的朋友。
首先,将AllFromCache()移至存储库类,并将其命名为GetAll()。它从缓存中检索的是存储库的实现详细信息,调用代码不应知道该信息。
这使测试您的过滤器类变得轻松而简单。它不再关心您从哪里得到它。
其次,将从数据库(或任何地方)获取数据的类包装在缓存包装器中。
AOP是一个很好的技术。这是它非常擅长的少数事情之一。
使用类似的工具 PostSharp之类的,您可以对其进行设置,以便所有标记有selected属性的方法都将被缓存。但是,如果这仅是您要缓存的内容,则无需深入了解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()只是...获取全部。从某处。