Django 测试 - 内部错误:当前事务被中止,命令被忽略直到事务块结束
在我的测试中,我不仅测试完美的情况,而且特别测试边缘情况和错误条件。所以我想确保一些唯一性约束起作用。
虽然我的测试和测试装置非常复杂,但我能够将问题追溯到以下示例,该示例不使用任何自定义模型。要重现该行为,只需将代码保存到tests.py 中并运行django 测试运行程序。
from django.contrib.auth.models import User
from django.db import IntegrityError
from django.test import TransactionTestCase
class TransProblemTest(TransactionTestCase):
def test_uniqueness1(self):
User.objects.create_user(username='user1', email='[email protected]', password='secret')
self.assertRaises(IntegrityError, lambda :
User.objects.create_user(username='user1', email='[email protected]', password='secret'))
def test_uniqueness2(self):
User.objects.create_user(username='user1', email='[email protected]', password='secret')
self.assertRaises(IntegrityError, lambda :
User.objects.create_user(username='user1', email='[email protected]', password='secret'))
具有单个测试方法的测试类可以工作,但如果有两个相同的方法实现,则会失败。 第一个测试抛出异常破坏了 Django 测试环境,并使以下所有测试失败。
我正在使用 Django 1.1 和 Ubuntu 10.04、Postgres 8.4 和 psycopg2。
Django 1.2 中还存在这个问题吗?
这是一个已知的错误还是我遗漏了什么?
In my tests I do not only test for the perfect case, but especially for edge cases and error conditions. So I wanted to ensure some uniqueness constraints work.
While my test and test fixtures are pretty complicated I was able to track the problem down to the following example, which does not use any custom models. To reproduce the behaviour just save the code into tests.py and run the django test runner.
from django.contrib.auth.models import User
from django.db import IntegrityError
from django.test import TransactionTestCase
class TransProblemTest(TransactionTestCase):
def test_uniqueness1(self):
User.objects.create_user(username='user1', email='[email protected]', password='secret')
self.assertRaises(IntegrityError, lambda :
User.objects.create_user(username='user1', email='[email protected]', password='secret'))
def test_uniqueness2(self):
User.objects.create_user(username='user1', email='[email protected]', password='secret')
self.assertRaises(IntegrityError, lambda :
User.objects.create_user(username='user1', email='[email protected]', password='secret'))
A test class with a single test method works, but fails with two identical method implementations.
The first test throwing exception breaks the Django testing environment and makes all the following tests fail.
I am using Django 1.1 with Ubuntu 10.04, Postgres 8.4 and psycopg2.
Does the problem still exist in Django 1.2?
Is it a known bug or am I missing something?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Django 有两种类型的
TestCase
:“plain”TestCase
和TransactionTestCase
。 文档有以下关于差异的说明他们两人之间:您正在使用
TransactionTestCase
来执行这些测试。切换到普通的TestCase
,如果您维护现有的测试代码,您将看到问题消失。为什么会出现这种情况?
TestCase
在事务块内执行测试方法。这意味着测试类中的每个测试方法将在单独的事务而不是同一事务中运行。当断言(或者更确切地说是内部的 lambda )引发错误时,它会随事务一起终止。下一个测试方法是在新事务中执行的,因此您不会看到收到的错误。但是,如果您要在相同测试方法中添加另一个相同的断言,您将再次看到错误:
这是因为第一个断言将被触发创建导致事务中止的错误。因此第二个无法执行。由于两个断言都发生在同一测试方法内,因此与之前的情况不同,尚未启动新事务。
希望这有帮助。
Django has two flavors of
TestCase
: "plain"TestCase
andTransactionTestCase
. The documentation has the following to say about the difference between the two of them:You are using
TransactionTestCase
to execute these tests. Switch to plainTestCase
and you will see the problem vanish provided you maintain the existing test code.Why does this happen?
TestCase
executes test methods inside a transaction block. Which means that each test method in your test class will be run inside a separate transaction rather than the same transaction. When the assertion (or rather thelambda
inside) raises an error it dies with the transaction. The next test method is executed in a new transaction and therefore you don't see the error you've been getting.However if you were to add another identical assertion in the same test method you would see the error again:
This is triggered because the first assertion will create an error that causes the transaction to abort. The second cannot therefore execute. Since both assertions happen inside the same test method a new transaction has not been initiated unlike the previous case.
Hope this helps.
我假设当您说“单个测试方法有效”时,您的意思是它失败,引发异常,但不会破坏测试环境。
也就是说,您正在关闭 AutoCommit 的情况下运行。在该模式下,默认情况下共享数据库连接上的所有内容都是单个事务,出现故障时需要通过 ROLLBACK 中止事务,然后才能启动新事务。我建议如果可能的话,打开自动提交——除非您需要将多个写入操作包装到一个单元中,否则关闭它就太过分了。
I'm assuming when you say "a single test method works", you mean that it fails, raises the exception, but doesn't break the testing environment.
That said, you are running with AutoCommit turned off. In that mode, everything on the shared database connection is a single transaction by default and failures require the transaction to be aborted via ROLLBACK before a new one can be started. I recommend turning AutoCommit on, if possible--unless you have a need for wrapping multiple write operations into a single unit, having it off is overkill.