2

问题

有没有办法为事务范围指定一个连接,以便可以回滚这个“上下文外”测试的效果?

背景

我正在使用 RestSharp 来测试 WebAPI 控制器。这是一个集成测试,通过向 API 发送请求进行测试,该请求通过存储库和服务层一直传播到数据层。换句话说,这故意不是单元测试。

测试创建了一个restClient实例:

    [TestInitialize()]
    public virtual void TestInitialize()
    {

        _client = new RestClient("http://localhost:24144");
        _client.CookieContainer = new System.Net.CookieContainer();

    }

然后客户端发出一些请求,完全不知道数据上下文(再次,故意):

 // pseudocode
 _client.DoThis();
 _client.DoThat();

此测试针对从 EF 代码优先迁移生成的测试数据库运行。我有一个空的种子方法,所以数据库是空的:

    protected override void Seed(TestAppDbContext context)
    {
        SqlConnection.ClearAllPools();
        context.Database.Delete();
        context.Database.CreateIfNotExists();
    }

问题

这只是我想运行的众多测试之一。目前我必须在测试之间删除/重新创建数据库,并确保 Api 测试在其他测试之后运行。由于它对数据上下文一无所知,因此我无法(或无法弄清楚如何)将所有测试代码包装在事务中以进行回滚。

我试过的

  • 在 TestInitialize 中新建一个事务范围并将其在 TestCleanup 中处理。这无济于事。
  • 在这个测试之后运行'update-database'只是为了好玩-但我总是得到'不能删除数据库,因为它当前正在使用',尽管我调用了ClearAllPools()。这不是我想关注的问题,但认为值得一提。
4

2 回答 2

1

几个月前我遇到了类似的问题,但TransactionScope由于您陈述的许多相同原因,我没有提出一个好的解决方案。

我最终在测试项目中自托管WebAPI。并且使用可以在每次测试运行之前删除和重新创建(和迁移)的 SQLCE 4 数据库。这已经运行了一段时间并且运行良好。

于 2013-05-05T21:23:07.350 回答
0

我能够使用 IsolationLevel.RepeatableRead 运行我的一些集成测试。

但是,涉及通过 API 更新实体的测试没有成功。仍在寻找完美的解决方案。

正如大卫的回答一样,每次测试复制一个新的数据库文件是迄今为止唯一完全有效的解决方案,但性能还有很多不足之处。特别是如果数据库模式已过时并且必须为每个测试迁移/播种。

NUnit 中的示例代码:

[SetUp]
public void TestSetUp()
{
    _transactionScope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions() {IsolationLevel = IsolationLevel.RepeatableRead, Timeout = TimeSpan.FromSeconds(5)});
}

[TearDown]
public void TestTearDown()
{
    // Roll back any changes made, per test.
    _transactionScope.Dispose();
}
于 2013-05-20T17:44:02.933 回答