Тестирование модуля Python CLI - программирование
Подтвердить что ты не робот

Тестирование модуля Python CLI

Я работаю над программой python Command-Line-Interface, и я нахожу это скучным при выполнении тестов, например, вот справочная информация о программе:

usage: pyconv [-h] [-f ENCODING] [-t ENCODING] [-o file_path] file_path

Convert text file from one encoding to another.

positional arguments:
  file_path

optional arguments:
  -h, --help            show this help message and exit
  -f ENCODING, --from ENCODING
                        Encoding of source file
  -t ENCODING, --to ENCODING
                        Encoding you want
  -o file_path, --output file_path
                        Output file path

Когда я внес изменения в программу и хочу что-то проверить, я должен открыть терминал, введите команду (с параметрами и аргументами), введите enter и посмотрите, произошла ли какая-либо ошибка во время бега. Если ошибка действительно возникает, я должен вернуться к редактору и проверить код от начала до конца, угадывая, где места ошибок, делайте небольшие изменения, пишите строки print вернитесь к терминалу, снова запустите команду...

Рекурсивный.

Итак, мой вопрос: какой лучший способ провести тестирование с помощью программы CLI, может ли быть так же легко как модульное тестирование с обычными сценариями python?

4b9b3361

Ответ 1

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

В любом случае, используя py.test, вот небольшой пример для тестирования преобразования latin1 в utf8 для pyconv::

# content of test_pyconv.py

import pytest

# we reuse a bit of pytest own testing machinery, this should eventually come
# from a separatedly installable pytest-cli plugin. 
pytest_plugins = ["pytester"]

@pytest.fixture
def run(testdir):
    def do_run(*args):
        args = ["pyconv"] + list(args)
        return testdir._run(*args)
    return do_run

def test_pyconv_latin1_to_utf8(tmpdir, run):
    input = tmpdir.join("example.txt")
    content = unicode("\xc3\xa4\xc3\xb6", "latin1")
    with input.open("wb") as f:
        f.write(content.encode("latin1"))
    output = tmpdir.join("example.txt.utf8")
    result = run("-flatin1", "-tutf8", input, "-o", output)
    assert result.ret == 0
    with output.open("rb") as f:
        newcontent = f.read()
    assert content.encode("utf8") == newcontent

После установки pytest ( "pip install pytest" ) вы можете запустить его следующим образом:

$ py.test test_pyconv.py
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- pytest-2.4.5dev1
collected 1 items

test_pyconv.py .

========================= 1 passed in 0.40 seconds =========================

Пример повторного использования некоторых внутренних механизмов собственного тестирования pytest, используя механизм крепления pytest, см. http://pytest.org/latest/fixture.html. Если вы забыли о деталях на мгновение, вы можете просто работать из-за того, что для запуска и запуска тестов предусмотрены "run" и "tmpdir". Если вы хотите играть, вы можете попытаться вставить неудачный assert-оператор или просто "утвердить 0", а затем посмотреть трассировку или вывести "py.test -pdb", чтобы ввести приглашение python.

Ответ 2

Короткий ответ - да, вы можете использовать модульные тесты и должны. Если ваш код хорошо структурирован, достаточно проверить каждый компонент отдельно, и если вам нужно всегда моргнуть sys.argv для имитации запуска его с разными аргументами.

Ответ 3

Итак, мой вопрос: какой лучший способ провести тестирование с помощью программы CLI, может ли быть так же просто, как и единичное тестирование с помощью обычных скриптов python?

Единственное различие заключается в том, что при запуске модуля Python в качестве script для его атрибута __name__ установлено значение '__main__'. В общем, если вы намерены запустить команду script из командной строки, она должна иметь следующую форму:

import sys

# function and class definitions, etc.
# ...
def foo(arg):
    pass

def main():
    """Entry point to the script"""

    # Do parsing of command line arguments and other stuff here. And then
    # make calls to whatever functions and classes that are defined in your
    # module. For example:
    foo(sys.argv[1])


if __name__ == '__main__':
    main()

Теперь нет никакой разницы, как вы его используете: как script или как модуль. Таким образом, внутри кода тестирования устройства вы можете просто импортировать функцию foo, вызвать его и сделать любые утверждения, которые вы хотите.

Ответ 4

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

Итак, реструктурируйте приложение, чтобы вы тестировали API, а не приложение. Но у вас может быть функциональный тест, который фактически запускает полное приложение и проверяет правильность вывода.

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

Ответ 5

Это не для Python специально, но то, что я делаю для проверки сценариев командной строки, - это запустить их с различными предопределенными входами и параметрами и сохранить правильный вывод в файле. Затем, чтобы проверить их, когда я вношу изменения, я просто запускаю новый script и вывожу вывод в diff correct_output -. Если файлы одинаковые, он ничего не выводит. Если они разные, это показывает, где. Это будет работать только в Linux или OS X; в Windows вам нужно будет получить MSYS.

Пример:

python mycliprogram --someoption "some input" | diff correct_output -

Чтобы сделать это еще проще, вы можете добавить все эти тестовые прогонки в свою целевую программу Make Make, которая, как я полагаю, у вас уже есть.;)

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

python mycliprogram --someoption "some input" | diff correct_output - || tput setaf 1 && echo "FAILED"

Ответ 6

Может быть, слишком мало, слишком поздно, но вы всегда можете использовать

import os.system
result =  os.system(<'Insert your command with options here'>
assert(0 == result)

Таким образом, вы можете запустить вашу программу, как если бы она была из командной строки, и оценить код завершения.

Ответ 7

Вы можете использовать стандартный модуль unittest:

# python -m unittest <test module>

или используйте nose в качестве рамки тестирования. Просто напишите классические unittest файлы в отдельном каталоге и запустите:

# nosetests <test modules directory>

Написание unittests легко. Просто следуйте онлайн-руководству для unittesting