2016-06-30 8 views
4

У меня проблема с моими модульными тестами и тем, как django управляет транзакциями.Тесты не выполняются с TransactionTestCase и pytest

В моем коде у меня есть функция:

def send(): 
    autocommit = transaction.set_autocommit(False) 
    try: 
     # stuff 
    finally: 
     transaction.rollback() 
     transaction.set_autocommit(autocommit) 

В моем тесте у меня есть:

class MyTest(TransactionTestCase): 
    def test_send(self): 
     send() 

Проблема, которую я имею, что мой test_send проходит успешно, но не 80% от моего друга тесты.

Кажется, сделка других тестов не удается

кстати я использую py.test запускать мои тесты

EDIT: Чтобы сделать вещи более ясно, когда я запускаю свои тесты только MyApp .test.test_module.py он работает нормально, и все 3 теста проходят, но когда я запускаю все свои тесты, большинство неудачных попыток, попытается создать тестовое приложение.

Также все мои тесты проходят со стандартным тестовым бегуном от django

EDIT2: Вот минимальный пример, чтобы проверить этот вопрос:

class ManagementTestCase(TransactionTestCase): 

    def test_transfer_ubl(self, MockExact): 
     pass 

class TestTestCase(TestCase): 

    def test_1_user(self): 
     get_user_model().objects.get(username="admin") 
     self.assertEqual(get_user_model().objects.all().count(), 1) 

Имейте в виду, существует datamigration, что добавляет «администратора» пользователя (TestTestCase преуспевает в одиночку, но не тогда, когда ManagmentTestCase выполняется раньше)

Кажется, autocommit не имеет к этому никакого отношения.

+0

Откуда этот метод send()? Пожалуйста, отправьте пример теста, который терпит неудачу после того, как вы вызвали send() – e4c5

+0

. Я написал метод отправки, другие тесты терпят неудачу, потому что когда они подсчитывают объекты в их изоляции, ломается – maazza

+0

Извините, если мой комментарий не ясен. Является ли метод отправки частью представления? Часть тестового кода? И, пожалуйста, добавьте образец теста, который не выполняется при выполнении вместе с этим – e4c5

ответ

4

Класс TestCase завершает тесты внутри двух атомных блоков. Поэтому невозможно использовать transaction.set_autocommit() или transaction.rollback(), если вы наследуете от TestCase.

Как говорят документы, вы должны использовать TransactionTestCase, если вы тестируете поведение транзакции конкретной базы данных.

+0

Я сделал, но это ломает большинство моих других тестов. – maazza

+0

Разделите свой тестовый класс на два класса. Используйте 'TransactionTestCase' для метода' test_send' и 'TestCase' для остальных. – Alasdair

+0

Я сделал это, у меня более 300 тестов – maazza

3

имеющий autocommit = transaction.set_autocommit(False) внутри send функция чувствует себя неправильно. Отключение транзакции выполняется здесь, предположительно, для целей тестирования, но эмпирическое правило заключается в том, чтобы сохранить тестовую логику вне вашего кода.

Как отметил @Alasdair, django docs заявляет, что «класс TestCase от Django также переносит каждый тест в транзакцию по соображениям производительности».

Неясно, проверяете ли вы конкретную логику транзакций базы данных или нет, если это так, то ответ Аласдаэра на использование TransactionTestCase - это путь.

В противном случае удалите переключатель контекста транзакции со всего stuff внутри вашей функции send.

Поскольку вы упомянули pytest в качестве вашего тестового бегуна, я бы также рекомендовал использовать pytest. Плагин Pytest-django имеет приятные функции, позволяющие выборочно устанавливать некоторые из ваших тестов на транзакции, используя markers.

pytest.mark.django_db(transaction=False) 

При установке плагина слишком много, то вы можете свернуть свой собственный transaction manage приспособление. Как

@pytest.fixture 
    def no_transaction(request): 
     autocommit = transaction.set_autocommit(False) 
     def rollback(): 
      transaction.rollback() 
      transaction.set_autocommit(True) 
     request.addfinalizer(rollback) 

Ваш test_send будет требовать no_transaction приспособления.

def test_send(no_transaction): 
    send() 
+0

Я использую autocommit = False + transaction.rollback, потому что я не хочу, чтобы некоторые вызовы внутри send() сохраняли модель в db, я хочу, чтобы db был нетронутым, это не имеет ничего общего с тестовой логикой, я пытался использовать pytest .mark без успеха, повторите попытку – maazza

+0

Я использовал pytest.mark.django_db (transaction = False), но теперь кажется, что база данных опустела во время тестов, что приводит к другим ошибкам в последующих тестах – maazza

+0

, вы получаете совершенно новую чистую slate database для каждого теста, если это не то, что вы хотите, вы можете явно использовать опцию '' keepdb'' из http://pytest-django.readthedocs.io/en/latest/database.html#django-db-keepdb – Meitham

Смежные вопросы