0

I have a function called get_choices() - that makes an api call - that is called inside a click.Choice() decorator for a click.Command() function called cli().

I want to test the command function cli() using click's CliRunner().invoke() method but avoid the api call inside get_choices().

Below is a minimal code to use. Make sure to have click installed using pip install click.

cli.py

from click import command, option, Choice


def get_choices():
    print("making an api call")
    return ["name_1", "name_2"]


@command()
@option(
    "--name",
    prompt=True,
    type=Choice(choices=get_choices()), # api call is made here
)

def cli(name):
    pass # Doesn't matter what happens here

test_cli.py

from unittest.mock import patch
import click
from click.testing import CliRunner


# This avoids the api call when importing cli below 
# but makes an api call itself when loading the module
patch("cli.get_choices", get_test_choices).start() 


def test_cli_behaves():
    runner = CliRunner()
    import cli

    # Replaces prod choices with test choices
    # I want to avoid using params[0]
    cli.cli.params[0].type = click.Choice(["name_test"]) 

    result = runner.invoke(cli.cli, args=["--name", "name_test"])
    print(result.stdout)
    assert result.exit_code == 0
    assert False

Is there a way to patch get_choices() before it's called inside the decorator when loading the module ?

I would like to avoid:

  • Any api call
  • Accessing cli.cli.params[0] since it's not clean and becomes cumbersome when there are many options added to the cli.

I am testing by attaching a debugger to the test and adding a breakpoint on the api call in get_choices() and can confirm an api call is made on the patch line or the import line if the patch isn't used.

I've read a lot of questions/answers about patching with decorators on stackoverflow, most notably this one which I've used to inspire my current solution, but none provides what I really want.

Edit: Does the answer to this question also apply in my case ?

houss
  • 7
  • 4

0 Answers0