Zasada pojedynczej odpowiedzialności jest tutaj twoim najlepszym przyjacielem.
Przede wszystkim przenieś AllFromCache () do klasy repozytorium i nazwij ją GetAll (). To, że pobiera z pamięci podręcznej, jest szczegółem implementacji repozytorium i nie powinno być znane kodowi wywołującemu.
To sprawia, że testowanie klasy filtrowania jest przyjemne i łatwe. Nie zależy już na tym, skąd go bierzesz.
Po drugie, owiń klasę, która pobiera dane z bazy danych (lub gdziekolwiek) w opakowanie buforujące.
AOP jest do tego dobrą techniką. To jedna z niewielu rzeczy, w których jest bardzo dobra.
Korzystając z narzędzi takich jak PostSharp , możesz to ustawić tak, aby każda metoda oznaczona wybranym atrybutem była buforowana. Jeśli jednak to jedyna rzecz, którą buforujesz, nie musisz sięgać tak daleko, jak posiadanie frameworka AOP. Wystarczy mieć repozytorium i opakowanie buforujące, które używają tego samego interfejsu i wstrzyknąć to do klasy wywołującej.
na przykład.
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
}
}
Zobacz, jak usunąłeś wiedzę dotyczącą implementacji repozytorium z menedżera produktów ProductManager? Zobacz także, w jaki sposób przestrzegałeś zasady pojedynczej odpowiedzialności, mając klasę, która obsługuje ekstrakcję danych, klasę, która obsługuje odzyskiwanie danych oraz klasę, która obsługuje buforowanie?
Możesz teraz utworzyć instancję menedżera produktu ProductManager z jednym z tych repozytoriów i uzyskać buforowanie ... lub nie. Jest to niezwykle przydatne później, gdy pojawi się mylący błąd, który, jak podejrzewasz, jest wynikiem pamięci podręcznej.
productManager = new ProductManager(
new SqlProductRepository()
);
productManager = new ProductManager(
new CachedProductRepository(new SqlProductRepository())
);
(Jeśli używasz kontenera IOC, nawet lepiej. Powinno być oczywiste, jak się przystosować.)
I w testach ProductManager
IProductRepository repo = MockRepository.GenerateStrictMock<IProductRepository>();
W ogóle nie trzeba testować pamięci podręcznej.
Teraz pojawia się pytanie: czy powinienem przetestować to CachedProductRepository? Sugeruję nie. Pamięć podręczna jest dość nieokreślona. Framework robi z nim rzeczy, które są poza twoją kontrolą. Na przykład po prostu usuwam z niego rzeczy, gdy się zapełni, na przykład. Skończysz z testami, które zawiodą raz na niebieskim księżycu i nigdy tak naprawdę nie zrozumiesz, dlaczego.
Po wprowadzeniu zmian, które zasugerowałem powyżej, naprawdę nie ma zbyt wiele logiki do przetestowania. Naprawdę ważny test, metoda filtrowania, będzie tam i całkowicie oderwany od szczegółów GetAll (). GetAll () po prostu ... dostaje wszystko. Skądś.