2012-04-13 81 views
6

我正在使用MSTest通过MySQL Connector和EntityFramework 4.3对MySQL 5.5.19数据库运行一些自动化测试。嵌套的TransactionScope在测试中失败

我试图在我的DB访问类库中使用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块时回滚自动发生。

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

大,所以我想我会改变我的AddDesert方法就像上面那样看起来除了我要嵌套事务范围,而不是使用环境之一,我的一些using线外表看起来是这样的:

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

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

但是我发现的是,我得到以下错误:

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

想法?

+0

请张贴堆栈跟踪和它发生在哪里的代码。 – usr 2012-04-13 17:09:23

回答

0

非常好的问题。当您在回滚后的testmethod内引用datacontext时,它将不可用。你需要压制这一点。您不需要指定所需的选项。这是默认选项。

测试方法:

[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); 
     } 
    } 

控制器的方法:

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()); 
      } 
     } 
    }