Django测试 - InternalError:当前事务被中止,命令被忽略直到事务块结束

gee*_*ekQ 2 django postgresql django-testing

在我的测试中,我不仅测试完美的情况,尤其是边缘情况和错误条件.所以我想确保一些唯一性限制工作.

虽然我的测试和测试装置非常复杂,但我能够将问题跟踪到以下示例,该示例不使用任何自定义模型.要重现行为,只需将代码保存到tests.py并运行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='user1@example.com', password='secret')
        self.assertRaises(IntegrityError, lambda :
            User.objects.create_user(username='user1', email='user1@example.com', password='secret'))

    def test_uniqueness2(self):
        User.objects.create_user(username='user1', email='user1@example.com', password='secret')
        self.assertRaises(IntegrityError, lambda :
            User.objects.create_user(username='user1', email='user1@example.com', password='secret'))
Run Code Online (Sandbox Code Playgroud)

具有单个测试方法的测试类可以工作,但是使用两个相同的方法实现失败.第一个测试抛出异常打破了Django测试环境,并使以下所有测试失败.

我正在使用Django 1.1和Ubuntu 10.04,Postgres 8.4和psycopg2.

问题在Django 1.2中是否仍然存在?

这是一个已知的错误还是我错过了什么?

Man*_*dan 5

Django有两种风格TestCase:"普通" TestCaseTransactionTestCase.该文档有以下几点说明它们之间的区别:

TransactionTestCaseTestCase除了数据库重置为已知状态的方式以及测试代码测试提交和回滚效果的能力之外,它们是相同的.A TransactionTestCase通过截断所有表并重新加载初始数据,在测试运行之前重置数据库.A TransactionTestCase可以调用commit和rollback,并观察这些调用对数据库的影响.

TestCase另一方面,A 不会截断表并在测试开始时重新加载初始数据.相反,它将测试代码包含在数据库事务中,该事务在测试结束时回滚.

您正在使用TransactionTestCase执行这些测试.切换到纯TestCase,你会看到消失在问题提供你保持现有的测试代码.

为什么会这样?TestCase在事务块中执行测试方法.这意味着测试类中的每个测试方法都将在单独的事务中运行,而不是在同一事务中运行.当断言(或更确切地说是lambda内部)引发错误时,它会随着事务而死亡.下一个测试方法在事务中执行,因此您没有看到您获得的错误.

但是,如果要在同一测试方法中添加另一个相同的断言,则会再次看到错误:

class TransProblemTest(django.test.TestCase):
    def test_uniqueness1(self):
        User.objects.create_user(username='user1', email='user1@example.com', password='secret')
        self.assertRaises(IntegrityError, lambda :
            User.objects.create_user(username='user1', email='user1@example.com', password='secret'))
        # Repeat the test condition.
        self.assertRaises(IntegrityError, lambda :
            User.objects.create_user(username='user1', email='user1@example.com', password='secret'))
Run Code Online (Sandbox Code Playgroud)

这是因为第一个断言将创建导致事务中止的错误.因此第二个不能执行.由于两个断言都发生在同一个测试方法中,因此与前一个案例不同,新事务尚未启动.

希望这可以帮助.