How to Mock Click CLI App Subcommands in Python

Simulate Click-style CLI subcommand calls in Python by using argparse with subparsers and mocking sys.argv in tests or scripts.

Easy Python 3.9+ Aug 9, 2026 Modern tooling 14 views 0 copies

Python code

33 lines
Python 3.9+
import sys
import argparse


def do_greet(args):
    print(f"Hello, {args.name}!")


def do_goodbye(args):
    print(f"Goodbye, {args.name}!")


def main():
    parser = argparse.ArgumentParser(prog="clickapp")
    subparsers = parser.add_subparsers(dest="command", required=True)

    greet_parser = subparsers.add_parser("greet", help="greet someone")
    greet_parser.add_argument("name", help="name to greet")
    greet_parser.set_defaults(func=do_greet)

    bye_parser = subparsers.add_parser("goodbye", help="say goodbye")
    bye_parser.add_argument("name", help="name to say goodbye to")
    bye_parser.set_defaults(func=do_goodbye)

    args = parser.parse_args()
    args.func(args)


if __name__ == "__main__":
    sys.argv = ["clickapp", "greet", "Alice"]
    main()
    sys.argv = ["clickapp", "goodbye", "Bob"]
    main()

Output

stdout
Hello, Alice!
Goodbye, Bob!

How it works

This example mimics Click's subcommand pattern using Python's stdlib argparse, which is handy for testing CLI logic without installing third-party packages. The argparse subparsers map each command to a function via set_defaults, and args.func(args) dispatches to the right handler. By temporarily replacing sys.argv before calling main(), you simulate different command-line invocations in a script or test. This approach keeps dependencies minimal while preserving the same user experience Click provides.

Common mistakes

  • Forgetting `required=True` in `add_subparsers`, which lets `main()` run without a command.
  • Not setting `dest` or using `set_defaults`, causing `args.func` to be missing.
  • Mutating `sys.argv` without restoring it afterward in tests, affecting other tests.
  • Assuming `click.testing.CliRunner` is the only way to mock CLI calls — this works with plain argparse too.

Variations

  1. Use `click.testing.CliRunner` in a test with a real Click-created CLI group.
  2. Write a unit test that monkeypatches `sys.argv` and calls `main()` directly.

Real-world use cases

  • Unit testing a CLI tool's subcommands without shelling out or needing a virtual terminal.
  • Simulating multiple CLI invocations in a CI script to verify help text and error handling.
  • Embedding CLI calls in a Python automation harness that runs different commands sequentially.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Modern tooling

Related tutorials and quizzes for this topic.