Как протестировать CLI-программу на Python с помощью click, cover.py и Tox? - PullRequest
0 голосов
/ 08 октября 2018

Я работаю над программой CLI, используя , нажмите , и я хочу начать добавлять некоторые тесты с анализом покрытия кода, используя cover.py .

IЯ думаю, что хорошим способом реализации тестов будет запуск самого CLI с использованием подпроцесса.Однако, cover.py сообщает об отсутствии покрытия кода, вероятно потому, что экземпляр Python, созданный подпроцессом, не имеет инструментария cover.py.

Я нашел эту ссылку , которая говорит, что я могу отброситьФайл sitecustomize.py в моем PYTHONPATH всегда заставляет Python начинать измерение покрытия, но я использую Tox для создания venv и запуска тестов.Я не смог найти никаких настроек Tox, которые справляются с этим.

Я нашел этот ответ , который говорит, что я должен просто запустить свой CLI через coverage run, но похоже, что это работает, только еслиуказан путь к скрипту Python, и я пытаюсь запустить свой CLI через точку входа, определенную в setup.py.т.е. я должен изменить все мои командные строки в тестовом коде с myprogram на coverage run myprogram/cli/cli.py.Я бы предпочел не делать этого, потому что я не ожидаю, что пользователи будут запускать программу.

Таким образом, кажется, что есть два варианта:

  1. выяснитьспособ заставить sitecustomize.py работать в среде Tox или

  2. во всех командных строках в тестовом коде использовать путь к сценарию вместо точки входа (вероятно, проще в долгосрочной перспективе, но делаеттесты чуть более хрупкие и труднее для понимания).Интересно, есть ли что-то еще, что я пропускаю.

1 Ответ

0 голосов
/ 08 октября 2018

CliRunner и правильная структура модульного тестирования - это путь.Вот пример настройки для PyTest , который использует плагин PyTest Coverage

test_click.py

from click.testing import CliRunner

from click_prog import hello


def test_hello_world():

    runner = CliRunner()
    result = runner.invoke(hello, ['--opt', 'An Option', 'An Arg'])
    assert result.exit_code == 0
    assert result.output == 'Opt: An Option  Arg: An Arg\n'

    result = runner.invoke(hello, ['An Arg'])
    assert result.exit_code == 0
    assert result.output == 'Opt: None  Arg: An Arg\n'


if __name__ == '__main__':
    test_hello_world()

click_prog.py

import click
import sys


@click.command()
@click.option('--opt')
@click.argument('arg')
def hello(arg, opt):
    """A Simple program"""
    click.echo('Opt: {}  Arg: {}'.format(opt, arg))


if __name__ == '__main__':
    hello(sys.argv[1:])

pytest.ini

[pytest]

# -- recommended but optional:
# python_files = tests.py test_*.py *_tests.py

Результаты теста:

===================== test session starts =====================
platform darwin -- Python 3.6.5, pytest-3.7.1, py-1.5.4, pluggy-0.7.1
rootdir: /Users/strauch/dev/fix_windows, inifile: pytest.ini
plugins: xdist-1.22.5, forked-0.2, cov-2.6.0
collected 1 item

test_click.py .                                         [100%]

---------- coverage: platform darwin, python 3.6.5-final-0 -----------
Name             Stmts   Miss  Cover
------------------------------------
click_prog.py        8      1    88%
test_click.py       12      1    92%
------------------------------------
TOTAL               20      2    90%


================== 1 passed in 0.07 seconds ===================
...