我有一对具有父/子关系的表-事件和incidentDetails。我有一个视图模型,其中包含来自这两个表的信息。我有一个业务层方法,它被传递给一个需要更新两个表的视图模型的实例。
因此,在这个方法中,我使用了EF6的新事务机制:
using (var transaction = this.db.Database.BeginTransaction())
{
try
{
// various database stuff
this.db.SaveChanges();
// more database stuff
this.db.SaveChanges();
// yet more database stuff
this.db.SaveChanges();
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
this.logger.logException(ex, "Exception caught in transaction, rolling back");
throw;
}
}所以,我的问题是。我该如何测试呢?
我使用的是微软的单元测试框架和Moq,模拟DBContexts和DbSet<>s也没什么问题,但我似乎想不出如何绕过事务的问题。
如果我不尝试模拟事务,我会得到一个InvalidOperationException:
“在应用程序配置文件中找不到名为xxx的连接字符串。”
这很有道理--没有应用程序配置文件,也没有任何数据库。
但是如果我试图模拟BeginTransaction(),我会得到初始化错误: NotSupportedException:
“非虚拟成员上的无效设置:M => m.Database.BeginTransaction”。
这让我在杂草中追逐,查看.NET方法的反编译,试图识别一些可能从可用的接口派生的类,或者其他东西,在那里我可以以某种方式注入一个模拟对象。
我并不是要对MS的事务性代码进行单元测试--我只是想确保对每个表中的相应记录进行了适当的更改。但现在看来,这看起来是不可测试的,而且任何使用事务的方法都是不可测试的。这只是一种痛苦。
我用谷歌搜索了一下,没有找到任何有用的东西。有没有人遇到过这个问题?有谁有关于如何继续的想法吗?
发布于 2013-12-28 05:00:50
测试这类东西总是很复杂的,但首先您应该问问自己,您是想要对业务逻辑进行单元测试,还是想要对应用程序进行集成测试。
如果你想单元测试你的逻辑,你基本上不应该尝试模拟实体框架,因为你不想测试EF,你只想测试你的代码,对吧?为此,模拟任何数据访问对象,只对您的业务逻辑进行单元测试。
但是,如果您想测试您的数据访问层是否工作,例如,如果您的代码可以处理您已经实现的所有CRUD操作,那么您应该对一个真实的数据库进行集成测试。在这种情况下,不要试图模拟任何数据访问对象(EF),只需对测试数据库或sql-express localDB运行测试即可。
发布于 2015-04-07 18:36:29
您可以将上下文和事务包装在一个接口中,然后通过某个提供程序类实现该接口:
public interface IDbContextProvider
{
YourContext Context { get; set; }
DbContextTransaction DbTransaction { get; set; }
void Commit();
void Rollback();
void BeginTransaction();
void SaveChanges();
}然后实现它:
public class EfContextProvider : IDbContextProvider
{
public EfContextProvider(YourContext context)
{
Context = context;
}
public YourContext Context { set; get; }
public DbContextTransaction DbTransaction { set; get; }
public void Commit()
{
DbTransaction.Commit();
}
public void Rollback()
{
DbTransaction.Rollback();
}
public void BeginTransaction()
{
DbTransaction=Context.Database.BeginTransaction();
}
public void SaveChanges()
{
Context.SaveChanges();
}
}所以现在给你的类提供IDbContextProvider依赖项并使用它(它也有内部的上下文)。可以用_contextProvider.BeginTransaction()替换using块;然后再用_contextProvider.Commit();或_contextProvider.Rollback();
发布于 2015-04-24 06:25:01
我花了几个小时试图弄清楚它,我相信它可以由MS Fakes直接完成,而不需要包装器或新的类。
您需要执行三个步骤:
这就是全部。
static void SetupDBTransaction()
{
System.Data.Entity.Fakes.ShimDbContextTransaction transaction = new System.Data.Entity.Fakes.ShimDbContextTransaction();
transaction.Commit = () => { };
transaction.Rollback = () => { };
System.Data.Entity.Fakes.ShimDatabase database = new System.Data.Entity.Fakes.ShimDatabase();
database.BeginTransactionIsolationLevel = (isolationLevel) =>{return transaction.Instance;};
System.Data.Entity.Fakes.ShimDbContext.AllInstances.DatabaseGet = (@this) => { return database.Instance; };
}https://stackoverflow.com/questions/20807668
复制相似问题