Тестирование Django - InternalError: текущая транзакция отменяется, команды игнорируются до конца блока транзакции - PullRequest
2 голосов
/ 30 августа 2010

В моих тестах я проверяю не только идеальный случай, но особенно крайние случаи и условия ошибок.Поэтому я хотел убедиться, что некоторые ограничения уникальности работают.

Хотя мой тест и тестовые приспособления довольно сложны, я смог отследить проблему до следующего примера, который не использует никаких пользовательских моделей.Чтобы воспроизвести это поведение, просто сохраните код в 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='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'))

Класс тестирования с одним методом тестирования работает, но не работает с двумя идентичными реализациями метода.Первое исключение при выдаче теста нарушает среду тестирования Django и приводит к сбою всех следующих тестов.

Я использую Django 1.1 с Ubuntu 10.04, Postgres 8.4 и psycopg2.

Существует ли проблема вDjango 1.2?

Это известная ошибка или я что-то упустил?

Ответы [ 2 ]

5 голосов
/ 30 августа 2010

Django имеет два вида TestCase: «обычный» TestCase и TransactionTestCase. документация содержит следующее утверждение о разнице между ними:

TransactionTestCase и TestCase идентичны, за исключением способа сброса базы данных до известного состояния и возможности тестового кода для проверки эффектов фиксации и отката. A TransactionTestCase сбрасывает базу данных до запуска теста путем усечения всех таблиц и перезагрузки исходных данных. TransactionTestCase может вызывать фиксацию и откат и наблюдать влияние этих вызовов на базу данных.

A TestCase, с другой стороны, не усекает таблицы и не перезагружает исходные данные в начале теста. Вместо этого он включает тестовый код в транзакцию базы данных, откат которой выполняется в конце теста.

Вы используете 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'))

Это вызвано тем, что первое утверждение создаст ошибку, которая приведет к прерыванию транзакции. Поэтому второе не может быть выполнено. Поскольку оба утверждения происходят внутри одного и того же метода тестирования, новая транзакция не была инициирована в отличие от предыдущего случая.

Надеюсь, это поможет.

1 голос
/ 30 августа 2010

Полагаю, когда вы говорите, что «работает один метод тестирования», вы имеете в виду, что он не работает, вызывает исключение, но не нарушает среду тестирования.

При этом вы работаете сАвтокоммит выключен.В этом режиме все в соединении с общей базой данных по умолчанию является одной транзакцией, и при сбоях транзакция должна быть прервана через ROLLBACK, прежде чем можно будет запустить новую.Я рекомендую включить AutoCommit, если это возможно - если вам не нужно объединять несколько операций записи в один блок, отключить его - это излишне.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...