Sto utilizzando un modello di repository generico Repository<TEntity>
in cui i repository accedono alle entità tramite un contesto. Quindi ho un livello di servizio che accetta un contesto nel costruttore. Ora posso avere più repository in un servizio, accedendo alle entità attraverso lo stesso contesto. Abbastanza standard. Questo è perfetto per le tabelle/viste che si associano alle entità, ma non posso analizzare i dati dei test che provengono dalle stored procedure.Come eseguire il mocking e il test dell'unità Stored procedure in EF
Questa è la mia messa a punto corrente:
IDbContext:
public interface IDbContext : IDisposable
{
IDbSet<T> Set<T>() where T : class;
DbEntityEntry<T> Entry<T>(T entity) where T : class;
void SetModified(object entity);
int SaveChanges();
// Added to be able to execute stored procedures
System.Data.Entity.Database Database { get; }
}
Contesto:
public class AppDataContext : DbContext, IDbContext
{
public AppDataContext()
: base("Name=CONNECTIONSTRING")
{
base.Configuration.ProxyCreationEnabled = false;
}
public new IDbSet<T> Set<T>() where T : class
{
return base.Set<T>();
}
public void SetModified(object entity)
{
Entry(entity).State = EntityState.Modified;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new BookingMap());
}
// Added to be able to execute stored procedures
System.Data.Entity.Database Database { get { return base.Database; } }
}
Repository Generico:
public class Repository<T> : IRepository<T> where T : class
{
private readonly IDbContext context;
public Repository(IDbContext context)
{
this.context = context;
}
public IQueryable<T> GetAll()
{
return this.context.Set<T>().AsQueryable();
}
public void Add(T entity)
{
this.context.Set<T>().Add(entity);
}
public void Delete(T entity)
{
this.context.Set<T>().Remove(entity);
}
public void DeleteAll(IEnumerable<T> entities)
{
foreach (var e in entities.ToList())
{
this.context.Set<T>().Remove(e);
}
}
public void Update(T entity)
{
this.context.Set<T>().Attach(entity);
this.context.SetModified(entity);
}
public void SaveChanges()
{
this.context.SaveChanges();
}
public void Dispose()
{
if (this.context != null)
{
this.context.Dispose();
}
}
}
Servizio:
public class BookingService
{
IDbContext _context;
IRepository<Booking> _bookingRepository;
public BookingService(IDbContext context)
{
_context = context;
_bookingRepository = new Repository<Booking>(context);
}
public IEnumerable<Booking> GetAllBookingsForName(string name)
{
return (from b in _bookingRepository.GetAll()
where b.Name == name
select b);
}
}
prova:
[TestClass]
public class BookingServiceTest
{
[TestMethod]
public void Test_Get_All_Bookings_For_Name()
{
var mock = new Mock<IDbContext>();
mock.Setup(x => x.Set<Booking>())
.Returns(new FakeDbSet<Booking>
{
new Booking { Name = "Foo" },
new Booking { Name = "Bar" }
});
BookingService _bookingService = new BookingService(mock.Object);
var bookings = _bookingService.GetAllBookingsForName(name);
Assert.AreEqual(2, bookings.Count(), "Booking count is not correct");
}
}
Questo è perfetto per le tabelle/viste che mappano alle entità, ma non riesco a dati di test di unità che viene attraverso le stored procedure.
Ho cercato su Internet e ho trovato la proprietà DbContext.Database
e sono in grado di eseguire stored procedure con la funzione .SqlQuery()
e associarle a un tipo di entità.
Questo è quello che ho aggiunto alla classe Repository<T>
:
public IEnumerable<T> SqlQuery(string storedProc, params object[] paramList)
{
return this.context.Database.SqlQuery<T>(storedProc, paramList);
}
e chiamare la funzione .SqlQuery()
nella mia classe di servizio:
public IEnumerable<Booking> GetAllBookings(string name)
{
return _bookingRepository.SqlQuery("EXEC GetAllBookings @name = {0}", name);
}
Questa grande opera (io sono in grado di ottenere alcuni dati) , ma la mia domanda è: come posso prendere in giro e testare questo?
È inutile prendere in giro una procedura memorizzata. Come faresti a sapere che la cosa reale funziona come previsto se il test unitario ha la luce verde? Se hai bisogno dei * dati * da una sproc per fare test unitari (non correlati alla logica dello sproc), puoi semplicemente creare dati fittizi. Per testare gli sproc, eseguire test di integrazione. –
Esattamente, ho solo bisogno del * data * dai test unitari di sproc per fare. Come posso creare i dati falsi? – Gaui
Penso che per cominciare, dovresti incapsulare sprocs nel tuo repository, Un servizio non dovrebbe sapere di SQL (o dei dettagli di persistenza). –