Quindi, alcune conclusioni. Ho pensato di scriverlo nel caso in cui fosse utile a qualcun altro che cercasse di usare insieme/unit test EF, Windsor e MVC.
Prima di tutto, poiché DbContext implementa entrambi i modelli di Repository e Unit of Work, è necessario verificare se queste implementazioni serviranno o se è necessario crearne di proprie.
Ho scelto di creare il mio repository, seguendo il modello DDD: uno per radice aggregata. I motivi: incapsulare il codice di query, per evitare che si diffonda nel livello dell'applicazione e per essere in grado di simulare più facilmente durante il test dei controller dell'applicazione. Ho creato un repository generico basato su IRepository<TEntity>
. Ci sono molti esempi là fuori. Ho trovato questo uno buono: http://architects.dzone.com/articles/implementing-repository
D'altro canto ho deciso di abbandonare il servizio IUnitOfWork, optando invece per l'implementazione predefinita. Tuttavia, ho creato un'astrazione IDbContext (non so perché Microsoft non l'abbia fatto da sé), così da poter prendere in giro DbContext durante il test dei servizi di repository.
Ho dato a IDbContext solo i membri di DbContext che volevo usare nel repository.Quindi:
public interface IDbContext: IDisposable
{
Database Database { get; }
DbEntityEntry Entry(object entity);
IDbSet<TEntity> Set<TEntity>() where TEntity : class;
int SaveChanges();
}
Poi ho creato una struttura di Windsor e di installazione per il mio IDbContext e servizi IRepository:
public class EntityFrameworkFacility: AbstractFacility
{
protected override void Init()
{
Kernel.Register(Component.For<IDbContext>()
.ImplementedBy<MyEntities>()
.LifestylePerWebRequest(),
Component.For(typeof(IRepository<>))
.ImplementedBy(typeof(Repository<>))
.LifestylePerWebRequest());
}
}
public class PersistenceInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility<EntityFrameworkFacility>();
}
}
Il pezzo finale è stato quello di estendere la classe contesto Entity Framework per implementare IDbContext, e ombra la set() per tornare IDbSet piuttosto che DbSet:
public partial class MyEntities : IDbContext
{
public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
{
return base.Set<TEntity>();
}
}
Con tutto questo in posto (e la registrazione ControllerFactory illustrato nella documentazione di Windsor), è diventa banale per ottenere Windsor iniettare oggetti IRepository (o IDbContext) in costruttori controllore, come richiesto:
public ControllerBase(IRepository<Contact> repo)
{
_repo = repo;
}
Nei test di unità Repository, un vero esempio repository può essere sostenuta con un IDbContext finto:
mocks = new MockRepository();
context = mocks.StrictMock<IDbContext>();
repo = new Repository<Contact>(context);
Nei test unità di controllo, un repository finto può essere utilizzato:
mocks = new MockRepository();
repo = mocks.StrictMock<IRepository<Contact>>();
ContactController controller = new ContactController(repo);
per chi ha segnato questo giù ... ti piacerebbe fornire un commento che dice perché? Se pensi di aver mancato il punto da qualche parte, potresti aiutarmi spiegando perché. –
Penso che sia stato rifiutato perché questa è una domanda di discussione, non proprio appropriata per StackOverflow, specialmente il primo punto. Il secondo punto può essere trovato nel sito di Castle Windsor, hanno una documentazione eccellente. Scritto il contenuto della tua domanda: la simulazione di DbContext per i test delle unità è [praticamente impossibile] (http://stackoverflow.com/a/13352779/861716). Io uso i progetti di "unit test" su un database per il test DAL oltre a progetti di test unitari puri per altri BL. Caste Windsor inietta contesti da una fabbrica di contesto, non interfacciata, servizi interfacciati, validatori ecc. –
Grazie per il tuo commento @GertArnold. Per quanto riguarda il problema del mocking, non voglio testare il DAL, ma essere in grado di fornire repository simulati al livello dell'applicazione (ad esempio i controller), per testarlo. La documentazione del castello è valida in generale, ma si occupa dell'integrazione con NHibernate ed è piuttosto schematica in quell'area. –