Ich verwende ein generisches Repository-Muster Repository<TEntity>
, in dem Repositorys über einen Kontext auf die Entitäten zugreifen. Dann habe ich eine Service-Schicht, die einen Context im Konstruktor akzeptiert. Jetzt kann ich mehrere Repositories in einem Service haben und über denselben Kontext auf die Entitäten zugreifen. Ziemlich Standard. Dies ist perfekt für Tabellen/Ansichten, die Entitäten zugeordnet sind, aber ich kann keine Testdaten verarbeiten, die gespeicherte Prozeduren durchlaufen.Spionage- und Komponententest Gespeicherte Prozeduren in EF
Dies ist meine aktuelle Setup:
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; }
}
Kontext:
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; } }
}
Generisches Repository:
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();
}
}
}
Service:
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);
}
}
Test:
[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");
}
}
Dies ist ideal für Tabellen/Ansichten, die Entitäten abzubilden, aber ich kann nicht Unit-Test-Daten über gespeicherte Prozeduren kommen.
Ich schaute auf das Internet und fand DbContext.Database
Eigenschaft und ich bin in der Lage, gespeicherte Prozeduren mit der .SqlQuery()
Funktion auszuführen und sie auf einen Entitätstyp abzubilden.
Dies ist, was ich in die Repository<T>
Klasse hinzugefügt:
public IEnumerable<T> SqlQuery(string storedProc, params object[] paramList)
{
return this.context.Database.SqlQuery<T>(storedProc, paramList);
}
Und die .SqlQuery()
Funktion in meiner Dienstklasse nennen:
public IEnumerable<Booking> GetAllBookings(string name)
{
return _bookingRepository.SqlQuery("EXEC GetAllBookings @name = {0}", name);
}
Dieses große Werk (ich bin in der Lage, einige Daten zu erhalten) Aber meine Frage ist, wie kann ich das simulieren und testen?
Es ist sinnlos, eine gespeicherte Prozedur nachzuahmen. Wie würdest du wissen, dass die reale Sache wie erwartet läuft, wenn der Komponententest ein grünes Licht hat? Wenn Sie die * Daten * von einem Sproc-Unit-Test benötigen (nicht mit der Logik des Sprocs verbunden), können Sie einfach Mock-Daten erstellen. Um sprocs zu testen, führen Sie Integrationstests durch. –
Genau, ich werde nur die * Daten * von den Sproc-to-Unit-Tests mit benötigen. Wie kann ich die Scheindaten erstellen? – Gaui
Ich denke, zu Beginn sollten Sie Sprocs in Ihr Repository kapseln, Ein Dienst sollte nicht über SQL (oder irgendwelche Persistenz Details) wissen. –