El principio de responsabilidad única es tu mejor amigo aquí.
En primer lugar, mueva AllFromCache () a una clase de repositorio y llámelo GetAll (). Lo que recupera de la memoria caché es un detalle de implementación del repositorio y no debe ser conocido por el código de llamada.
Esto hace que probar su clase de filtrado sea agradable y fácil. Ya no le importa de dónde lo obtengas.
En segundo lugar, ajuste la clase que obtiene los datos de la base de datos (o donde sea) en un contenedor de almacenamiento en caché.
AOP es una buena técnica para esto. Es una de las pocas cosas en las que es muy bueno.
Usando herramientas como PostSharp , puede configurarlo para que cualquier método marcado con un atributo elegido se almacene en caché. Sin embargo, si esto es lo único que está almacenando en caché, no necesita ir tan lejos como tener un marco de AOP. Solo tenga un Repositorio y un Contenedor de almacenamiento en caché que use la misma interfaz e inyecte eso en la clase de llamada.
p.ej.
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
}
}
¿Ves cómo has eliminado el conocimiento de implementación del repositorio del ProductManager? Vea también cómo se ha adherido al Principio de responsabilidad única al tener una clase que maneja la extracción de datos, una clase que maneja la recuperación de datos y una clase que maneja el almacenamiento en caché.
Ahora puede crear una instancia del ProductManager con cualquiera de esos Repositorios y obtener el almacenamiento en caché ... o no. Esto es increíblemente útil más tarde cuando obtienes un error confuso que sospechas que es el resultado del caché.
productManager = new ProductManager(
new SqlProductRepository()
);
productManager = new ProductManager(
new CachedProductRepository(new SqlProductRepository())
);
(Si está utilizando un contenedor de COI, aún mejor. Debería ser obvio cómo adaptarse).
Y, en sus pruebas de ProductManager
IProductRepository repo = MockRepository.GenerateStrictMock<IProductRepository>();
No es necesario probar el caché en absoluto.
Ahora la pregunta es: ¿Debo probar ese CachedProductRepository? Sugiero que no. El caché es bastante indeterminado. El marco hace cosas que están fuera de su control. Por ejemplo, simplemente eliminando cosas cuando se llena demasiado, por ejemplo. Vas a terminar con pruebas que fallan una vez en una luna azul y nunca entenderás realmente por qué.
Y, habiendo hecho los cambios que he sugerido anteriormente, realmente no hay tanta lógica para probar allí. La prueba realmente importante, el método de filtrado, estará allí y completamente abstraída de los detalles de GetAll (). GetAll () solo ... obtiene todo. Desde algún lugar.