首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >模拟数据库事务?

模拟数据库事务?
EN

Stack Overflow用户
提问于 2013-12-28 04:51:50
回答 6查看 18.4K关注 0票数 25

我有一对具有父/子关系的表-事件和incidentDetails。我有一个视图模型,其中包含来自这两个表的信息。我有一个业务层方法,它被传递给一个需要更新两个表的视图模型的实例。

因此,在这个方法中,我使用了EF6的新事务机制:

代码语言:javascript
复制
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的事务性代码进行单元测试--我只是想确保对每个表中的相应记录进行了适当的更改。但现在看来,这看起来是不可测试的,而且任何使用事务的方法都是不可测试的。这只是一种痛苦。

我用谷歌搜索了一下,没有找到任何有用的东西。有没有人遇到过这个问题?有谁有关于如何继续的想法吗?

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2013-12-28 05:00:50

测试这类东西总是很复杂的,但首先您应该问问自己,您是想要对业务逻辑进行单元测试,还是想要对应用程序进行集成测试。

如果你想单元测试你的逻辑,你基本上不应该尝试模拟实体框架,因为你不想测试EF,你只想测试你的代码,对吧?为此,模拟任何数据访问对象,只对您的业务逻辑进行单元测试。

但是,如果您想测试您的数据访问层是否工作,例如,如果您的代码可以处理您已经实现的所有CRUD操作,那么您应该对一个真实的数据库进行集成测试。在这种情况下,不要试图模拟任何数据访问对象(EF),只需对测试数据库或sql-express localDB运行测试即可。

票数 13
EN

Stack Overflow用户

发布于 2015-04-07 18:36:29

您可以将上下文和事务包装在一个接口中,然后通过某个提供程序类实现该接口:

代码语言:javascript
复制
public interface IDbContextProvider
{
    YourContext Context { get; set; }
    DbContextTransaction DbTransaction { get; set; }
    void Commit();
    void Rollback();
    void BeginTransaction();
    void SaveChanges();
}

然后实现它:

代码语言:javascript
复制
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();

票数 12
EN

Stack Overflow用户

发布于 2015-04-24 06:25:01

我花了几个小时试图弄清楚它,我相信它可以由MS Fakes直接完成,而不需要包装器或新的类。

您需要执行三个步骤:

  1. 为DbContextTransaction创建填充对象,并绕过其提交和回滚方法来为数据库创建填充对象。并绕过其BeginTransaction方法以返回在步骤1中创建的DbContextTransaction填充对象。
  2. 绕开所有实例的DbContext.Database属性以返回在步骤2中创建的数据库填充对象。

这就是全部。

代码语言:javascript
复制
    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; };
    }
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20807668

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档