O Princípio da Responsabilidade Única é seu melhor amigo aqui.
Primeiro, mova AllFromCache () para uma classe de repositório e chame-a GetAll (). A recuperação do cache é um detalhe de implementação do repositório e não deve ser conhecido pelo código de chamada.
Isso torna fácil e fácil testar sua classe de filtragem. Não se importa mais de onde você está conseguindo.
Segundo, agrupe a classe que obtém os dados do banco de dados (ou qualquer outro local) em um wrapper de cache.
AOP é uma boa técnica para isso. É uma das poucas coisas em que é muito bom.
Usando ferramentas como o PostSharp , você pode configurá-lo para que qualquer método marcado com um atributo escolhido seja armazenado em cache. No entanto, se essa é a única coisa que você está armazenando em cache, não precisa ir tão longe quanto ter uma estrutura de AOP. Apenas tenha um Repositório e um Caching Wrapper que usem a mesma interface e os injetem na classe de chamada.
por exemplo.
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
}
}
Veja como você removeu o conhecimento de implementação do repositório do ProductManager? Veja também como você aderiu ao Princípio de Responsabilidade Única ao ter uma classe que lida com extração de dados, uma classe que lida com recuperação de dados e uma classe que lida com cache.
Agora você pode instanciar o ProductManager com um desses repositórios e obter o cache ... ou não. Isso é incrivelmente útil mais tarde, quando você recebe um bug confuso que suspeita ser resultado do cache.
productManager = new ProductManager(
new SqlProductRepository()
);
productManager = new ProductManager(
new CachedProductRepository(new SqlProductRepository())
);
(Se você estiver usando um contêiner de COI, melhor ainda. Deve ser óbvio como se adaptar.)
E, em seus testes do ProductManager
IProductRepository repo = MockRepository.GenerateStrictMock<IProductRepository>();
Não há necessidade de testar o cache.
Agora a pergunta é: devo testar esse CachedProductRepository? Eu sugiro que não. O cache é bastante indeterminado. A estrutura faz coisas que estão fora de seu controle. Por exemplo, basta remover coisas dele quando estiver muito cheia, por exemplo. Você terminará com testes que falharão uma vez na lua azul e nunca entenderá realmente o porquê.
E, tendo feito as alterações sugeridas acima, não há realmente muita lógica para testar lá. O teste realmente importante, o método de filtragem, estará lá e completamente abstraído dos detalhes de GetAll (). GetAll () apenas ... recebe tudo. De algum lugar.