Почему тест django терпит неудачу только при запуске полного набора тестов?

У меня есть тест в Django 1.5, который проходит в этих условиях:

  • при самостоятельном выполнении
  • когда выполняется полный TestCase
  • когда все мои тесты приложений запущены

Но это не удается, когда полный набор тестов запущен с python manage.py test. Почему это может произойти?

В аберрантном тесте используются django.test.Client to POST некоторые данные для конечной точки, а затем проверка проверяет, что объект был успешно обновлен. Могло ли какое-то другое приложение модифицировать тестовый клиент или сами данные?

Я пробовал отлаживать отпечатки, и я вижу, что все данные отправляются и получаются, как ожидалось. Конкретный отказ - это исключение, которое не возникает, которое возникает, когда я пытаюсь извлечь обновляемый объект из db. Как ни странно, в самом обработчике исключений я могу запросить все объекты этого типа и увидеть, что на самом деле существует целевой объект.

Edit:

Моя проблема была решена, когда я обнаружил, что я запрашиваю целевой объект id и User, а не id и UserProfile, но мне все же кажется, что это будет работать в некоторых случаях, но неудача в других.

Я также обнаружил, что тест завершится с ошибкой python manage.py test auth <myapp>

Ответ 1

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

У меня был один тест, который проходил бы изолированно, но с ошибкой выполнялся как часть моего полного набора тестов. В одной из моих функций просмотра я использовал функцию Django send_mail(). В моем тесте, вместо того, чтобы присылать мне письмо каждый раз, когда я запускал свои тесты, я patch ed send_mail в своем методе тестирования:

from mock import patch
...

def test_stuff(self):
    ...

    with patch('django.core.mail.send_mail') as mocked_send_mail:

    ...

Таким образом, после вызова функции view, я могу проверить, что send_mail был вызван с помощью:

self.assertTrue(mocked_send_mail.called)

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

Решение было простым: вместо исправления django.core.mail.send_mail я просто закрепил версию, которая уже была импортирована в мой views.py - myapp.views.send_mail. Другими словами:

with patch('myapp.views.send_mail') as mocked_send_mail:
...

Ответ 2

Попробуйте это, чтобы помочь вам отладить:

./manage.py test --reverse

В моем случае я понял, что в одном тесте были обновлены некоторые данные, которые могут привести к сбою следующего теста.

Ответ 3

Другая возможность заключается в том, что вы отключили сигналы в setUp тестового класса и не подключались повторно в tearDown. Это объясняет мою проблему.

Ответ 4

Существует много недетерминизма, который может исходить из тестов, связанных с базой данных.

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

result = pull_stuff_from_database()
assert result[0] == 1
assert result[1] == 2

будет терпеть неудачу, потому что result[0] == 2 and result[1] == 1.

Другим источником странного недетерминированного поведения является автоинкремент id вместе с сортировкой некоторого вида.

Скажем, каждый тест создает два элемента, и вы сортируете по имени элемента, прежде чем делать утверждения. Когда вы запускаете его самостоятельно, "Item 1" и "Item 2" работают нормально и проходят тест. Однако при запуске всего пакета один из тестов генерирует "Item 9" и "Item 10". "Пункт 10" сортируется перед "Элементом 9", поэтому ваш тест завершится неудачно, потому что заказ перевернут.