Тест блокировки с помощью CliRunner в клике ⇐ Python

Программы на Python
Anonymous
Тест блокировки с помощью CliRunner в клике

Сообщение Anonymous »

Я пытаюсь написать функциональные тесты для CLI на основе Click, используя pytest и click.testing. Моя программа использует click.prompt — команду блокировки, ожидающую ввода пользователя. При запуске программы из сценария bash программа корректно завершает работу, как только стандартный ввод достигает EOF, но при тестировании с помощью CliRunner тест зависает на неопределенный срок, поскольку исполнитель не обрабатывает EOF в таким же образом.
Вот упрощенный пример, демонстрирующий проблему. Программа должна запрашивать число определенное количество раз, определяемое опцией --size. Однако из-за преднамеренной ОШИБКИ программа запрашивает больше входных данных, чем предусмотрено, в результате чего тест никогда не завершается:

Код: Выделить всё

import click
import click.testing

@click.command()
@click.option("-s", "--size", type=int, default=3)
def main(size):
BUG = 5
for i in range(size + BUG):
value = click.prompt("", type=int)
click.echo(f"{value}")

def test_cli():
runner = click.testing.CliRunner()
result = runner.invoke(main, ["-s", "5"], input="1\n2\n3\n4\n5\n")
assert result.stdout == "1\n2\n3\n4\n5\n"
assert result.exit_code == 0

if __name__ == "__main__":
main()
test_cli()
При запуске программы непосредственно из оболочки она ведет себя ожидаемым образом. Если введено меньше входных данных, чем количество подсказок, программа завершается с прерыванием по достижении EOF:

Код: Выделить всё

$ echo -e "1\n" | python foo.py
Enter a number: 1
Enter a number: Enter a number: Aborted!
Однако при использовании CliRunner для тестирования тест зависает на неопределенный срок после достижения недостающих входных данных. В отличие от поведения в bash, CliRunner не обрабатывает EOF и продолжает ждать дополнительных входных данных. Это становится серьезной проблемой в средах непрерывной интеграции (CI), где ожидается, что тесты будут корректно завершаться.
Вот что я пробовал до сих пор:
  • Имитация EOF с помощью \xff: я пытался добавить \xff ко входным данным, чтобы имитировать конец ввода, но проблема осталась.
    Использование BytesIO: я попытался использовать объект BytesIO для входного потока, но тест все равно зависает.
  • Применение таймаута: я добавил @pytest.mark.timeout(1) перед функцией test_cli, чтобы обеспечить таймаут. Хотя это предотвращает бесконечное зависание теста, оно не решает основную проблему, связанную с тем, что click.prompt не обрабатывает EOF.
Как решить проблему, когда click.prompt в тесте неправильно обрабатывает EOF при использовании click.testing.CliRunner? Существует ли надежный способ имитировать EOF в тестах, чтобы тест завершался при исчерпании входных данных, как это происходит при запуске из сценария bash?


Подробнее здесь: https://stackoverflow.com/questions/790 ... r-in-click

Вернуться в «Python»