2008-10-07 141 views
4

在这个asp.net中,我正在清理它可能发生死锁。我想确保代码正确处理它们,所以我试图编写NUnit测试来触发死锁.....我可以在Nunit中创建数据库死锁测试吗?

DAO被实体分割。每个实体都有一组测试,这些测试由Startup()和Teardown()方法包围,这些方法创建一个事务范围,然后在测试完成后将其回滚。这适用于其他任何事情,但对于死锁完全没有用处。

如何使用可以可靠复制的TransactionScope和SQL2000(即涉及MSDTC)来设置和运行“死锁”测试? 更多详细信息:我知道有这样一种情况,即如果两个用户调用具有不同的特定数据值的两个函数,那么死锁可以得到的结果。我如何在NUNIT中模拟这个 - 并且使得始终发生

是的,我的确从“为什么不停止发生在第一个位置的死锁”行动计划开始,但我无法控制可能发生死锁的代码 - 我只是调用函数他们可能会陷入僵局。

回答

2

如果您的死锁导致抛出异常,您希望使用模拟对象来模拟抛出的异常。

的基本想法是,你告诉你的Mock对象框架(我喜欢TypeMock)抛出一个异常,而不是,是这样的:

MockObject mo = MockManager.MockObject(typeof(MyDeadlockException)); 
mock.ExpectAndThrow("MyMethod", (MyDeadlockException)mo.Object); 

的想法基本上是其他嘲讽框架相同。

+0

我喜欢这个想法。我有模拟框架的想法,但从未使用过。我假设一个“ExpectAndThrow”方法实际上会导致异常被抛出,所以我的代码可以捕获它。我会进一步研究。 – 2008-10-10 10:29:17

+0

这正是它所做的。我没有使用它,但如果你有预算问题,Rhino.Mocks是免费的:http://ayende.com/projects/rhino-mocks.aspx – 2009-08-21 14:16:08

0

如果您的交易中有一项测试只是等待5分钟,那该怎么办?或者,您只需编写一个测试来启动事务,创建新记录,然后更新该记录而不提交。然后,开始新的事务并尝试读取已创建并且当前正在更新的记录。你会在那里陷入僵局。

+0

在同一线程中创建两个事务不能使用TransactionScope产生死锁。如果我创建了一个txn,然后创建另一个不提交第一个,第二个嵌套在第一个..... – 2008-10-08 07:38:57

0

如果您手动锁定表并始终将其锁定,该怎么办?那么,你对该表采取的任何行动都会产生死锁情况?

+0

“手动”使用MSDTC创建事务并不简单。当然,我可以在查询分析器中开始一个事务,但这不是一个分布式事务,发生的一切就是它阻止MSDTC事务从事任何数据库工作,直到我在查询分析器中“回滚”。 – 2008-10-08 07:39:34

0

来到这个盲目,但它有可能在您的TestSetup方法实际上创建一个SQLConnection到您的数据库?那么,使用它,你可以发出一个命令来锁定表或采取一些行动来锁定一个记录或页面?那样,它会超出你正在进行的任何其他交易吗?看起来这将是一个你已经考虑过的选项。我错过了你的情况?

+0

我认为创建死锁的先决条件将是发行交易的两个独立流程。在一个进程中创建“人造”锁并不会强制造成死锁 - 它强制“等待”资源变为空闲。我希望有一种方法可以在NUNIT中进行模拟。 – 2008-10-08 07:43:36

+0

我没有看到在手动强制之外的方法。现在,这可能意味着你在NUnit中手动强制它,但你仍然手动强制它。您只需创建生成死锁场景的情况。 – 2008-10-08 18:00:49

0

对于单元测试,您可能希望避免实际使用数据库。你怎么知道你有一个僵局。你应该测试一下条件,告诉你有一个死锁并在你的测试中创建它。

一个模拟是一个理想的模仿,如果你调用一个服务,它会返回一个错误。只需让模拟返回您所期望的错误。如果您正在等待超时或其他事情,那么同样的事情也适用。

一般来说,单元测试应该只运行在被测试的代码上,不要依赖任何其他代码或组件。这就是说 - 数据库本质上是另一个组件,你可能正在做一些使用nunit来驱动它们的功能测试。

在这种情况下,您实际上必须创建死锁情况,但锁定记录或表,然后调用试图使用相同记录并处理响应的组件。