Il principio di responsabilità singola è il tuo migliore amico qui.
Prima di tutto, sposta AllFromCache () in una classe di repository e chiamalo GetAll (). Il fatto che recuperi dalla cache è un dettaglio di implementazione del repository e non dovrebbe essere conosciuto dal codice chiamante.
Questo rende la prova della tua classe di filtraggio piacevole e facile. Non importa più da dove lo stai ricevendo.
In secondo luogo, racchiudere la classe che ottiene i dati dal database (o ovunque) in un wrapper di memorizzazione nella cache.
AOP è una buona tecnica per questo. È una delle poche cose in cui è molto bravo.
Usando strumenti come PostSharp , puoi configurarlo in modo che qualsiasi metodo contrassegnato con un attributo scelto verrà memorizzato nella cache. Tuttavia, se questa è l'unica cosa che stai memorizzando nella cache, non hai bisogno di andare fino al punto di avere un framework AOP. Basta avere un repository e un wrapper per la memorizzazione nella cache che utilizzano la stessa interfaccia e lo inseriscono nella classe chiamante.
per esempio.
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
}
}
Vedi come hai rimosso la conoscenza dell'implementazione del repository dal ProductManager? Vedi anche come hai aderito al principio di responsabilità singola avendo una classe che gestisce l'estrazione dei dati, una classe che gestisce il recupero dei dati e una classe che gestisce la memorizzazione nella cache?
Ora puoi creare un'istanza del ProductManager con uno di questi repository e ottenere la memorizzazione nella cache ... oppure no. Questo è incredibilmente utile in seguito quando si ottiene un bug confuso che si sospetta sia il risultato della cache.
productManager = new ProductManager(
new SqlProductRepository()
);
productManager = new ProductManager(
new CachedProductRepository(new SqlProductRepository())
);
(Se stai usando un contenitore IOC, anche meglio. Dovrebbe essere ovvio come adattarsi.)
E, nei test di ProductManager
IProductRepository repo = MockRepository.GenerateStrictMock<IProductRepository>();
Non è necessario testare la cache.
Ora la domanda diventa: dovrei testare quel CachedProductRepository? Suggerisco di no. La cache è piuttosto indeterminata. Il framework fa cose che sono fuori dal tuo controllo. Ad esempio, rimuovendo le cose da esso quando diventa troppo pieno, per esempio. Finirai con prove che falliscono una volta in una luna blu e non capirai mai davvero perché.
E, dopo aver apportato le modifiche che ho suggerito sopra, non c'è davvero molta logica da testare. Il test veramente importante, il metodo di filtraggio, sarà lì e completamente astratto dai dettagli di GetAll (). GetAll () solo ... ottiene tutto. Da qualche parte.