Модульное тестирование команд оболочки, вызываемых в скрипте Python - PullRequest
0 голосов
/ 29 августа 2018

Я пишу модульные тесты (используя Python 3.7, Pytest 3.6 и tox 3.0) для функции, которая собирает серию команд оболочки в виде списка строк, а затем выполняет их с помощью модуля subprocess. Команды оболочки выполняют следующее:

  • создает имя файла из аргументов функции.
  • cd в данный каталог.
  • проверяет файл с определенным именем и удаляет его, если он существует.
  • создает новый файл с тем же именем.
  • выполняет программу и направляет вывод в новый файл.

Мой тест прямо сейчас - это проверка модуля подпроцесса, а затем утверждение, что он был вызван со списком строк, который содержит все ожидаемые команды с некоторыми аргументами теста.

Есть ли способ проверить, что команды делают то, что они должны? Сейчас мой тест только проверяет, совпадает ли список команд, которые я передаю в модуль подпроцесса, с тем, который я утверждал, что это так. Это не говорит мне, являются ли команды правильными для того, чего я пытаюсь достичь . Скорее, это всего лишь проверка того, могу ли я записать одну и ту же строку в два разных исходных файла.

Можно ли имитировать побочные эффекты, которые, как я ожидаю, будут иметь команды оболочки?

Ответы [ 2 ]

0 голосов
/ 30 апреля 2019

Ваш вопрос объединяет две интересные темы: а) тестирование кода, сгенерированного из генератора кода, и б) тестирование кода оболочки.

Для тестирования кода из генератора в принципе вам необходимо выполнить следующее: i) проверить, что генератор создает ожидаемый код - что вы уже сделали, ii) проверить, что код отрывает / отрывает генератор склейки фактически ведут себя (независимо и в комбинации) так, как задумано (в вашем случае это кусочки кода оболочки, которые в итоге вместе образуют корректную программу оболочки) - это часть о тестировании кода оболочки, которая будет рассмотрена ниже и iii) проверить правильность входов, управляющих генератором.

Это сопоставимо с компилятором: i) код компилятора, ii) фрагменты кода сборки, которые компилятор объединяет для получения результирующей программы сборки, и iii) исходный код, который предоставляется компилятору для его получения. скомпилирован. После того как i), ii) и iii) протестированы, редко требуется также тестировать код сборки (то есть на уровне кода сборки). В частности, исходный код iii) идеально тестируется тестовыми средами на одном и том же языке программирования.

В вашем случае не очень понятно, как выглядит часть iii) и как ее можно проверить.

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

В вашем случае это означает, что фрагменты кода оболочки должны быть проверены на интеграцию в различных целевых операционных системах (т. Е. Не изолированы от операционной системы). Кроме того, различные способы, с помощью которых генератор соединяет эти фрагменты, также должны быть проверены на интеграцию, чтобы увидеть, работают ли они вместе в операционной системе.

Однако может существовать шелл-код, подходящий для модульного тестирования. Это, например, код, выполняющий вычисления внутри оболочки, или манипуляции со строками. Я бы даже рассмотрел шелл-код с вызовами некоторых фундаментальных инструментов, таких как basename, как подходящий для модульного тестирования (интерпретируя такие инструменты как часть «стандартной библиотеки», если хотите). В вашем случае, как вы описываете сгенерированный код оболочки

создает имя файла из аргументов функции.

Это звучит как один из примеров хорошего кандидата для шелл-кода «модульного тестирования»: эту функцию создания имени файла можно поместить в функцию оболочки, а затем протестировать отдельно.

0 голосов
/ 29 августа 2018

С pytest-mock вы можете запросить прибор mocker и затем шпион на subprocess функции:

def test_xxx(mocker):
    mocker.spy(subprocess, 'call')
    subprocess.call(...)
    assert subprocess.call.call_count == 1

P.S. Тесты с побочными эффектами, как правило, являются плохой практикой, поэтому я рекомендую запускать все команды оболочки в tmpdir (приспособление pytest, создающее временный каталог).

...