Почему тест 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", поэтому ваш тест завершится неудачно, потому что заказ перевернут.