How to test commands added to `@click.group` dynamically?

50 Views Asked by At

The question regards mocking, in general. This is a quite new topic to me. I stucked when developing some tests for a simple CLI based on the click library...

Assume I have a file structure as follows:

.
├── src/
│   └── project/
│       ├── cli/
│       │   ├── commands/
│       │   │   └── __init__.py  # <- empty
│       │   ├── __init__.py
│       │   └── main.py
│       └── __init__.py
└── tests/
    └── cli/
        └── test_main.py

In the project.cli.main module I have a simple click group with the commands parameters populated as the module is imported:

# src/project/cli/main.py

import click

from project.cli import commands


@click.group(
    commands=[
        command
        for command in commands.__dict__.values()
        if isinstance(command, click.Command)
    ],
)
@click.pass_context
def cli(context):
    pass

That's it. Now I want to write a unit test to check whether adding/implementing some commands to project.cli.commands actually adds those commands to the cli group's "registry".

Tools I use: pytest and pytest-mock (mocker fixture).

This is what I tried:

# tests/test_main.py

import click


def test_cli_commands(mocker):
    # Arrange
    class CommandsMock:
        @click.command()
        def command_1():
            pass

    mocker.patch("project.cli.main.commands", CommandsMock())
    
    # Act
    from project.cli.main import cli  # noqa: F401
    
    # Assert
    assert "command-1" in cli.commands

The test fails. I get:

FAILED tests/cli/test_main.py::test_reactor_cli_commands - AssertionError: assert 'command-1' in {}

Any ideas how to make it passing? Thanks in advance!

0

There are 0 best solutions below