CliRunner in practice
Write pytest tests for a Click command — happy path, error path, and output content assertions — using CliRunner.
- Write a pytest-style test using CliRunner that asserts on exit code 0
- Assert that output contains expected text
- Test the error path and assert on a non-zero exit code
A test for a Click command follows the same structure as any other test:
arrange (set up the command and runner), act (invoke), assert (check the
result). The only difference is that the result comes from result.output
and result.exit_code rather than a return value.
The command under test
Here is a small Click command to test:
import click
@click.command()
@click.argument("name")
@click.option("--loud", is_flag=True, help="Print in uppercase.")
def greet(name, loud):
"""Greet NAME."""
if not name.strip():
raise click.UsageError("Name cannot be blank.")
msg = f"Hello, {name}!"
click.echo(msg.upper() if loud else msg)This is enough to write three meaningful tests: the happy path, the --loud
flag, and an invalid argument.
Three test patterns
Happy path:
def test_greet_default():
runner = CliRunner()
result = runner.invoke(greet, ["Alice"])
assert result.exit_code == 0
assert "Hello, Alice!" in result.outputVariation (--loud flag):
def test_greet_loud():
runner = CliRunner()
result = runner.invoke(greet, ["Alice", "--loud"])
assert result.exit_code == 0
assert "HELLO, ALICE!" in result.outputError path (missing argument):
def test_greet_missing_arg():
runner = CliRunner()
result = runner.invoke(greet, [])
assert result.exit_code == 2 # Click's exit code for UsageError / missing arg
assert "Missing argument" in result.outputExit code 2 is Click's standard for usage errors — missing required
arguments, type mismatches, and click.UsageError. Exit code 1 is the
convention for runtime errors (the command ran but something went wrong).
Exit code 0 means success.
Try it
When a Click command raises an unhandled exception, result.exit_code is
1 and result.exception holds the exception object. Add
assert result.exception is None to the happy-path tests so any unexpected
crash causes a clear test failure rather than a silent wrong exit code.
Where to go next
Next: mocking stdin and env — using CliRunner's input= parameter for
confirmation prompts and env= for environment variable injection.