(Это кросспания из моего блога: https://blog.meadsteve.dev/programming/2021/01/01/yepling-formilective/ )
Я писал небольшой инструмент CLI и хотел попробовать Типер Отказ Я большой поклонник быстрой API, поэтому я думал, что библиотека CLI из того же автора стоило взгляда. Этот пост блога будет покрывать шаблон, который я закончил использовать, чтобы помочь с тестированием.
Приложение и первая попытка тестов
Я не буду идти в слишком много подробностей о моей реальной проблеме, но я оказался чем-то вроде следующего:
import typer def my_command(some_input: str): typer.echo(f"Starting up") # Do the first thing typer.echo(f"Result of first thing was X") # Do the second thing typer.echo(f"Result of second thing was X") # Do some clean up typer.echo(f"All done") if __name__ == "__main__": typer.run(my_command)
Значение в коде я писал, был выходом Typer.echo
. Поэтому я хотел проверить это. Первоначально в моих тестах я был заплаткой обезьян Typer.echo
и утверждать, что это соответствует тому, что Я хотел. Это было в порядке, но я не люблю исправления обезьян с издевательствами, как это часто становится очень запутанный и сложный.
Решение? Уступая.
Так как у меня уже была функция, представляющая призыв моей команды, я думал, что это будет Действительно приятно, если бы я мог просто вернуть вывод. Тогда я мог бы назвать функцию и утверждать что это выпустило то, что я хотел. Тем не менее, учитывая, что вполне значительные задержки могут происходит между каждой из моих эхо-заявлений, которые я действительно не хотел ждать до конца Чтобы получить весь мой выход. Так вместо этого доходность
казалось хорошим кандидатом. Я обновил свой код смотреть что-то подобное:
@dataclass class Echo: message: str def my_command(some_input: str): yield Echo(f"Starting up") # Do the first thing yield Echo(f"Result of first thing was X") # Do the second thing yield Echo(f"Result of second thing was X") # Do some clean up yield Echo(f"All done")
Теперь моя функция была генератором. Код выглядел почти идентичным, что было приятно. Мне нужно было добавить слой сверху, чтобы запустить этот генератор Но это было не слишком сложно:
import typer def run_cli(generator_func): for output_line in generator_func(): typer.echo(output_line.message)
И теперь мои тестовые случаи могут выглядеть так:
def test_something(): actual = list(my_command("input")) expected = [ Echo("first message"), Echo("second message"), Echo("etc.") ] assert actual == expected
Я считаю это успехом. Мои тесты стали намного проще, что было моей первоначальной целью. Кроме того, my_command
Функция потеряла свою зависимость от Типер
Библиотека и стало Агностик к тому, как ввод отображается пользователю (хотя это не было действительно моей первоначальной целью).
Оригинал: “https://dev.to/meadsteve/yielding-for-testability-in-python-1j20”