Как распространить модульные тесты django на несколько файлов?

126
  • У меня есть приложение python-django
  • Я использую среду модульного тестирования
  • Тесты расположены в файле "tests.py" в каталоге модуля.
  • Я провожу тесты через ./manage.py test app

Сейчас..

  • tests.pyФайл становится довольно большой / комплекс / грязный
  • Я хотел бы разбить tests.pyна более мелкие наборы тестов ...

Как?

Джон Ми
источник

Ответы:

47

В Django 1.6 поведение изменилось, поэтому создавать пакет больше нет необходимости. Просто назовите свои файлы test*.py.

Из документации Django 1.7

Когда вы запускаете свои тесты, тестовая утилита по умолчанию находит все тестовые примеры (то есть подклассы unittest.TestCase) в любом файле, имя которого начинается с test, автоматически создает набор тестов из этих тестовых примеров, и запустите этот пакет.

Из документации Django 1.6 ,

Обнаружение тестов основано на обнаружении тестов, встроенных в модуль unittest. По умолчанию это обнаружит тесты в любом файле с именем «test * .py» в текущем рабочем каталоге.

Предыдущее поведение из документации Django 1.5 :

Когда вы запускаете свои тесты, тестовая утилита по умолчанию находит все тестовые примеры (то есть подклассы unittest.TestCase) в models.py и tests.py, автоматически создает набор тестов из этих тестовых примеров, и запустите этот пакет.

Существует второй способ определить набор тестов для модуля: если вы определите функцию с именем suite () в models.py или tests.py, средство запуска тестов Django будет использовать эту функцию для создания набора тестов для этого модуля. Это соответствует предлагаемой организации для модульных тестов. См. Документацию Python для получения дополнительных сведений о том, как создать сложный набор тестов.

OSA
источник
4
В django 2.6 он ничего не обнаруживает…
LtWorf
2
В настоящее время я использую Django 1.10, и я хотел поместить все свои test*.pyфайлы в папку, названную testsдля сохранения папки в чистоте - это возможно, но вы должны запустить, ./manage.py test app.testsи весь относительный импорт должен подняться на уровень ( from .modelsстановится from ..models).
Скотт Стивенс,
123

Обратите внимание, что этот подход больше не действует в Django 1.6, см. Этот пост .

Вы можете создать testsпапку ___init___.pyвнутри (чтобы она стала пакетом). Затем вы добавляете туда свои файлы .py для сплит-теста и импортируете их все в ___init___.py.

То есть: замените test.pyфайл модулем, который выглядит и действует как файл:

Создайте testsкаталог под рассматриваемым приложением

приложение
App \ models.py
App \ views.py
App \ тесты
Приложение \ тесты \ __ init__.py
App \ \ bananas.py Проведены тестовые
App \ \ apples.py Проведены тестовые

Импортируйте подмодули в app\tests\__init__.py:

from bananas import *
from apples import *

Теперь вы можете использовать ./manage.py, как если бы все они были в одном файле:

./manage.py test app.some_test_in_bananas
Томаш Зелиньски
источник
1
Doh. Вы имели в виду создать модуль «тесты» под тестируемым мной приложением; не новое приложение под названием тесты. Я понял теперь. Потрясающие. Спасибо!
Джон Ми
@John: Я больше не могу узнать свой ответ! :-) Но вы совершенно правы, что это было слишком расплывчато, даже если правильно - ваши примеры проясняют это, вопреки моей первоначальной формулировке.
Tomasz Zieliński
2
@Tomasz .. Твои слова все еще там - целиком. Я просто немного конкретизировал это с тех пор, как ты поставил меня на правильный путь.
John Mee
@John: Я совсем не злился, если ты это имеешь в виду :) Было просто забавно увидеть мой собственный ответ в немного другой форме
Томаш Зелиньски
4
@jMyles, если под «обычным запуском тестов django» вы имеете python manage.py test myappв виду, то на самом деле этот ответ работает нормально. (только что попробовал)
Кирк Уолл
27

Ответ, изложенный Томашем, правильный. Однако может оказаться утомительным убедиться, что импортированные __init__.pyфайлы соответствуют вашей файловой структуре.

Чтобы автоматически определять все тесты в папке, вы можете добавить это в __init__.py:

import unittest

def suite():   
    return unittest.TestLoader().discover("appname.tests", pattern="*.py")

Это позволит вам запустить, ./manage.py test appnameно не будет выполнять определенные тесты. Для этого вы можете использовать этот код (также в __init__.py):

import pkgutil
import unittest

for loader, module_name, is_pkg in pkgutil.walk_packages(__path__):
    module = loader.find_module(module_name).load_module(module_name)
    for name in dir(module):
        obj = getattr(module, name)
        if isinstance(obj, type) and issubclass(obj, unittest.case.TestCase):
            exec ('%s = obj' % obj.__name__)

Теперь вы можете запускать все свои тесты через manage.py test appили определенные черезmanage.py test app.TestApples

Брайс Дреннан
источник
Где разместить второй кусок?
rh0dium
Обе части входят в__init__.py
Брайс Дреннан
Обратите внимание, что если какое-либо из имен ваших тестовых пакетов совпадает с именами модулей верхнего уровня, которые импортируются во время тестового запуска, фрагмент pkgutil приведет к сбою импорта, поскольку тесты добавляются как sys.modules[packagename]. Быстрый обходной путь - delлюбой, который вызывает проблемы после вышеуказанного. (Или вы можете переименовать свои папки;))
Пол Фенни
Это здорово, но я столкнулся с ошибкой, когда при запуске теста уровня приложения ( python manage.py test appName) второй бит кода вызывал ошибку, указывающую, что __path__он недоступен. Я избежал этого, заключив второй фрагмент в if '__path__' in locals():чек, и это помогло. Спасибо за ответ!
alukach
1
+1 это также гарантирует, что файл инициализации соответствует общим стандартам кодирования, т.е. не имеет * или неиспользуемого импорта
Мартин Б.
13

Просто сделайте вашу структуру каталогов такой:

myapp/
    __init__.py
    tests/
        __init__.py
        test_one.py
        test_two.py
        ...
    ...

И python manage.py test myappбудет работать как положено.

spiderlama
источник
5

http://docs.python.org/library/unittest.html#organizing-tests рассказывает о разделении файлов на модули, а в разделе прямо над ним есть пример.

Джим Девиль
источник
2
«Немного лишнее», которое я ищу по сравнению с rtfm, - это среда настроек django, база данных и фикстуры для тестов.
John Mee
2

Не нужно ничего кодировать в init. Просто создайте подкаталог в своем приложении. Единственное требование - не называть это тестами * Например

app/
app/__init_.py
app/serializers.py
app/testing/
app/testing/__init__.py
app/testing/tests_serializers.py
MaxBlax360
источник
1
Почему нельзя назвать это тем, что начинается с «тестов»?
Serp C
Я использую этот ответ с Django 1.11.4. Причины для его использования: (1) Файл «app / testing / __ init__.py» остается пустым и (2) Команда остается основным «тестовым приложением python manage.py»
rprasad
2

В Django 2.2 простым и довольно хорошим решением может быть создание testпапки внутри приложения, в которую вы можете поместить свои связанные test_...pyфайлы, просто добавив __init__.pyих в testпапку.

Gabor
источник
1

Если у вас более сложная настройка или вы не хотите использовать from ... import *операторы suite-type , вы можете определить функцию, вызываемую в вашем tests.py (или tests / __ init__.py), которая возвращает экземпляр unittest.TestSuite.

Джоэл Кросс
источник
0

Я думаю, что ./manage.py testпросто выполняет все трюки с тестами (в django> = 1.7).

Если ваши организации тестов о группировке и Cherrypicking и вы поклонник noseиспользования Джанго носа :

python manage.py test another.test:TestCase.test_method

Если вы знаете нос, то вы гораздо лучше знаете, как использовать подстановочные знаки для всех ваших файлов.

PS

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

Евгений Якимович
источник
0

У меня есть два файла. Одно есть, tests.pyа другое есть test_api.py. Я могу запустить их индивидуально, как показано ниже.

   manage.py test companies.tests
   manage.py test companies.test_api

Обратитесь к ответу @osa о соглашении об именах файлов.

КТА
источник