c# - 嵌套的 TransactionScope 在测试中失败

标签 c# mysql entity-framework transactions mstest

我正在使用 MSTest 通过 MySQL 连接器并使用 EntityFramework 4.3 针对 MySQL 5.5.19 数据库运行一些自动化测试。

我正在尝试在我的数据库访问类库中使用 TransactionScope 以在需要时执行回滚。此外,在我的测试代码中,我希望在每次测试之前使用 TransactionScope 将数据库放回已知状态。我使用 TestInitializeTestCleanup 方法来完成此操作。那些看起来像这样:

[TestInitialize()]
public void MyTestInitialize()
{
   testTransScope = new TransactionScope(TransactionScopeOption.RequiresNew);
}

[TestCleanup()]
public void MyTestCleanup()
{
   Transaction.Current.Rollback();
   testTransScope.Dispose();
}

基于初始化函数中 TransactionScope 对象的构造,我相信我应该得到一个新的事务范围(不存在“环境”范围,所以我相信这个“.RequiresNew”在这里在技术上并不重要,因为“.Required”会产生相同的结果。由于我没有指定超时值,它为我提供了默认超时,据我所知是 60 秒。有足够的时间我要运行的给定测试。

我有一个名为 AddDessert(DessertBiz dessertBizObject) 的函数,部分看起来像这样:

using (var transScope = new TransactionScope(TransactionScopeOption.Required))
{
   try
   {
      // ...
      context.Desserts.Add(dessert);
      context.SaveChanges();
      var dessertId = dessert.Id;
      DoOtherDessertStuff(dessertId, dessertBizObject);
      transScope.Complete();
   }
   catch (InvalidOperationException ex)
   {
      Console.WriteLine(ex.ToString());
   }
}

这个函数被我的一个测试调用。

因为我在这里指定了 TransactionScopeOption.Required,所以我希望它将使用 MyTestInitialize 函数创建的“环境”事务范围。

我的测试安排使此 DoOtherDessertStuff 函数失败并抛出异常,因此不会发生对 transScope.Complete(); 的调用并且回滚在 AddDessert 函数中退出 using block 时自动发生。

我在这里遇到的问题是,因为它使用了在 MyTestInitialize 函数中创建的环境事务范围,所以我的测试 Assert 调用不会发生,因为事务范围回滚发生了——至少这是我认为正在发生的事情。我验证了 Transaction.Current.TransactionInformation.StatusTransactionStatus.Aborted,所以我很确定这就是正在发生的事情。

太好了,所以我想我会更改我的 AddDesert 方法,使其看起来与上面完全一样,除了我会嵌套事务范围而不是使用环境范围,一些我的 using 行看起来像这样:

using (var transScope = new TransactionScope(TransactionScopeOption.RequiresNew))

这里的目的是我可以嵌套这些事务范围,让我的生产代码中发生回滚,然后仍然检查我的测试代码中的 Assert

但我发现我收到以下错误:

System.IO.IOException: 无法从传输连接读取数据: 连接尝试失败,因为连接方在一段时间后没有正确响应,或者建立的连接失败,因为连接的主机没有响应。

想法?

最佳答案

很好的问题。当您在回滚后在测试方法中引用数据上下文时,它将不可用。你需要压制它。您不需要指定必需的选项。这是默认选项。

测试方法:

  [TestMethod()]
    public void CreateTestCheckContextCorrectly()
    {
        MailJobController target = new MailJobController();

        target.AddDessert("dessert for Omer");
        //With suppress, even if you rollback ambient trans, suppress will ignore ambient trans. You need to reference new context, previous context from controller may be disposed.
        using (var suppressscope = new TransactionScope(TransactionScopeOption.Suppress))
        {
            var newdbcontextref = new DbEntities();

            int recordcount = newdbcontextref.StatusDefinitions.Where(x => x.Name == "dessert for Omer").Count();

            Assert.AreEqual(0, recordcount);
        }
    }

Controller 方法:

 public void AddDessert(string dessert)
   {
       using (var transScope = new TransactionScope())
       {
           try
           {
               // ...
               StatusDefinition statusDefinition = new StatusDefinition() {Name = dessert};
               db.StatusDefinitions.AddObject(statusDefinition);
               db.SaveChanges();
               Console.WriteLine("object id:"+statusDefinition.StatusDefinitionId);
               throw new Exception("hee hee");
               transScope.Complete();
           }
           catch (Exception ex)
           {
               Console.WriteLine(ex.ToString());
           }
       }
   }

关于c# - 嵌套的 TransactionScope 在测试中失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10145151/

相关文章:

c# - 如何使用 .NET 数据工厂 SDK (C# ) 在启用 DeVOPS GIT 存储库的 Azure 数据工厂中发布管道?

c# - 在WinForms应用程序中绘制数千条线的最快方法是什么

c# - 将图像加载到 wp7 中的应用程序栏

c# - 有没有一种方法可以通过具有不同订购量的 IQueryable 进行订购

c# - 我应该拆分我的 edmx 吗?

c# - 有没有办法在不添加 .dbml 文件的情况下使用 Linq to SQL?

mysql - 使用命令行客户端将多个文本文件及其部分标题导入Mysql表

mysql - 如何让 MySQL 在 OSX 上运行?

mysql - 存储过程 : Get month

linq - 根据用户输入构建动态 linq 查询