在C#中使用自动化测试用例,我们需要在每次测试后恢复数据库快照。问题是,当运行多个测试时,它会失败,因为“当其他用户正在使用数据库时,无法更改数据库状态。”
我们在恢复之前使用SqlConnection.ClearAllPools();
,但在第四次测试之后,它不会再次恢复运行,并且似乎池停止清除。 (为什么四个?见编辑2)
如何让这更可靠?
修改
也许我应该提供有关该系统的更多信息。这些是服务的单元集成测试。测试引用服务dll(没有服务引用,我们直接访问服务方法)。因此,除了在每个测试块之后恢复数据库快照之外,测试中没有SQL。
这是一项服务,因此我们无法完全管理连接。我们有一个中心点,我们在其中创建数据库对象,我们从中获取DbCommands来执行存储过程。
在SQL studio中使用sp_who2
,我观察到以下内容:前四个测试块(每个块由ClearAllPools()
和快照恢复分隔),数据库有一个会话,但是从第五个测试块开始,有三个针对它的会话。 (为什么?这可能是问题的线索。)(快照恢复打开了与主数据库的附加连接。)所有打开的连接都有状态休眠,等待命令,甚至是阻止快照恢复连接的命令。
编辑2
为什么五个?我认为测试用例会随机执行,但我错了。我找到了罪魁祸首。打开多个连接,系统仅使用最后一个连接,其他连接处于挂起状态,直到退出后才会清除。
答案 0 :(得分:6)
在恢复快照之前,请以单用户模式设置数据库:
ALTER DATABASE <mydb> SET SINGLE_USER WITH ROLLBACK IMMEDIATE
如果您不希望终止打开的连接,可以通过在没有回滚选项的情况下运行它来使命令等待
ALTER DATABASE <mydb> SET SINGLE_USER
这是一个黑客攻击,但是很难让你的快照恢复一致地工作。 (一旦被咬,两次害羞。)
答案 1 :(得分:5)
我使用不同的方法。我在一个事务中运行测试,该事务将在每个测试结束时处理(回滚)。 这样您就不需要在每个测试会话中丢弃数据库,因为db总是“干净”。 在C#中,您可以创建一个TransactionScope并在测试后进行处理,或者(更好)如果您使用xUnit.net,则可以使用AutoRollback属性。
答案 2 :(得分:0)
我们正在做同样的事情。在每次测试之前从备份恢复数据库:
ALTER DATABASE <dbname> SET OFFLINE WITH ROLLBACK IMMEDIATE
DROP DATABASE <dbname>
RESTORE DATABASE <dbname> FROM DISK= ...
对于数据库不存在的情况,我们还使用
检查数据库IF DB_ID (N'<dbname>') IS NOT NULL
希望这有帮助