我正在使用ms unit test对我正在使用Entity Framework的项目进行单元测试。我可以使用以下示例来模拟它 Msdn 但我有一个场景,我需要在实体框架中使用事务 以下列方式
Var tran = testdbcontext.Database.BeginTransaction()
并且测试失败,因为testdbcontext的数据库为null。
我想知道我们是否可以以某种方式嘲笑它以使其正常工作
答案 0 :(得分:1)
使用链接的MSDN文章作为参考,您会注意到它们已经抽象了DbContext。使用相同的思路,您还应该抽象出事务的创建。
首先创建事务对象的预期功能的抽象。
/// <summary>
/// Wraps access to the transaction object on the underlying store connection
/// </summary>
public interface IDbContextTransaction : IDisposable {
/// <summary>
/// Commits the underlying store transaction
/// </summary>
void Commit();
/// <summary>
/// Rolls back the underlying store transaction
/// </summary>
void Rollback();
}
这反映了您希望从数据库事务中获得的功能。
对于生产,您可以使用这样的实现来包装您想要使用的实际对象。
public class DbContextTransactionWrapper : IDbContextTransaction {
private DbContextTransaction dbContextTransaction;
public DbContextTransactionWrapper(DbContextTransaction dbContextTransaction) {
this.dbContextTransaction = dbContextTransaction;
}
public void Commit() {
dbContextTransaction.Commit();
}
public void Rollback() {
dbContextTransaction.Rollback();
}
public void Dispose() {
if(dbContextTransaction != null) {
dbContextTransaction.Dispose();
dbContextTransaction = null;
}
}
}
DbContext抽象将包括创建事务的能力......
public interface IStoreAppContext : IDisposable {
DbSet<Product> Products { get; }
int SaveChanges();
void MarkAsModified(Product item);
IDbContextTransaction BeginTransaction();
}
并且实现将使用包装器
public class StoreAppContext : DbContext, IStoreAppContext
{
public StoreAppContext() : base("name=StoreAppContext")
{
}
public DbSet<Product> Products { get; set; }
public void MarkAsModified(Product item)
{
Entry(item).State = EntityState.Modified;
}
public IDbContextTransaction BeginTransaction() {
return new DbContextTransactionWrapper(Database.BeginTransaction());
}
}
这样,在您的单元测试中,您可以通过模拟框架或虚假实现来模拟事务的创建,您将直接在抽象的DbContext上调用它。
假设testdbcontext
的类型为IStoreAppContext
,那么您的通话就像......
IDbContextTransaction tran = testdbcontext.BeginTransaction();
这将使您能够访问界面上定义的tran.Commit()
和tran.Rollback()
,并且可以轻松进行测试。