При планировании рефакторинга приложения мы увидели, что некоторые модули, которые были у нас в другом проекте, можно было повторно использовать для того, что нам было нужно. Я быстро подумал, что я могу просто переместить это в отдельный пакет, добавить его в оба проекта в качестве зависимости, и боги DRY будут довольны мной.

Позже в тот же день совершенно неожиданно я понял, что проект рефакторинга - последний из имеющихся у нас, работающий на Python 2.7 (я знаю #SHAME), в то время как все остальные используют 3.5. Попытка обновить версию python - не вариант (эй, у нас еще есть два года согласно pythonclock), так что это была прекрасная возможность попробовать tox.

Из официальных документов:

tox - это универсальный инструмент командной строки для управления и тестирования virtualenv, который можно использовать для:

- проверка правильности установки вашего пакета с разными версиями Python и интерпретаторами

- запуск тестов в каждой из сред, настройка выбранного инструмента тестирования

- выступает в качестве внешнего интерфейса к серверам непрерывной интеграции, значительно сокращая шаблонный код и объединяя тестирование на основе CI и оболочки.

Чтобы начать использовать tox, нам нужно сделать три вещи:

  1. Установите tox с pip install tox.
  2. Создайте файл setup.py для нашего пакета.
  3. Создайте файл tox.ini на том же уровне каталога, что и файл setup.py.

Установить

Первый шаг - это просто выполнение команды pip install tox, вы можете установить ее в собственном virtualenv с остальными требованиями к пакету.

setup.py

Следующим шагом будет создание файла setup.py, наш выглядит примерно так:

from setuptools import find_packages, setup
setup(
    name='my-tox-tested-package',
    version='0.0.1',
    packages=find_packages(exclude=['tests']),  # Include all the python modules except `tests`.
    description='My custom package tested with tox',
    long_description='A long description of my custom package tested with tox',
    install_requires=[
        'Django>=1.11.0',
        'djangorestframework>=3.6.0',
        # Additional requirements, or parse the requirements file and add it here
    ],
    classifiers=[
        'Programming Language :: Python',
    ],
    entry_points={
        'pytest11': [
            'tox_tested_package = tox_tested_package.fixtures'
        ]
    },
)

Это действительно просто, он определяет метаданные пакета и его требования. Этот файл позволит нам установить наш пакет как зависимость в других проектах, что мы можем сделать локально с pip install -e <path_to_package>, или загрузить его на GitHub или pypi и добавить в наш файл требований. Вы можете найти больше информации об упаковке в Руководстве пользователя Python Packaging и в документации по инструментам установки.

Вам может быть интересно узнать об аргументе entry_point, переданном функции setup, запись pytest11 используется для того, чтобы плагины pytest могли устанавливаться другими, в нашем случае он предоставляет настраиваемые фикстуры pytests, которые могут использоваться проектами, устанавливающими наш пакет.

tox.ini

Наконец, нам нужно создать файл tox.ini, опять же, вот пример того, который мы используем:

# tox (https://tox.readthedocs.io/) is a tool for running tests
# in multiple virtualenvs. This configuration file will run the
# test suite on all supported python versions. To use it, "pip install tox"
# and then run "tox" from this directory.
[tox]
envlist = py27, py35
[testenv]
commands =
  pytest {posargs: tests}
  isort --check-only --diff --recursive --skip .tox --skip migrations
  flake8
deps =
  -rrequirements.txt

Это действительно простой пример. envlist в разделе tox указывает, что мы хотим запускать команды раздела testenv для двух версий python, в этом примере наши цели - 2.7 и 3.5. Tox будет работать, создав отдельный виртуальный сервер для каждой версии и установив наш пакет в них обоих.

Если мы хотим тестировать одну среду за раз, мы можем передать флаг -e с именем среды, например, чтобы протестировать только python 3.5, который мы выполняем:

$ tox -e py35

Свойство commands в разделе testenv определяет, какой tox будет выполняться для тестирования нашего кода. Для каждой среды будет вызвано следующее:

  • pytest для unittest.
  • isort для проверки порядка импорта.
  • flake8 для линтинга.

Следует отметить, что команда pytest сопровождается символом {posargs: tests}, который захватывает аргументы команды tox после --, передает их в pytest и добавляет tests в список аргументов.

Звонок вроде:

$ tox -- -x

Выполнит команду:

pytest -x tests

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

Каждый раз, когда мы меняем зависимости проекта, мы должны сказать tox воссоздать наши среды и установить новые зависимости, используя флаг --recreate.

$ tox --recreate

Распараллеливание с Travis CI

Чтобы воспользоваться преимуществами матрицы сборки Travis CI, нам просто нужно добавить различные среды, которые мы хотим использовать, в файл travis.yml, таким образом мы запустим два задания и выполним тесты для каждой среды. в параллели.

language: python
install:
  - pip install tox
matrix:
  include:
    - python: 2.7
      env:
       - TOX_ENV=py27
    - python: 3.5
      env:
        - TOX_ENV=py35
script: tox -e $TOX_ENV

Более сложные примеры

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