Skip to content

Commit

Permalink
Tests: Add test to guarantee CLI is reachable
Browse files Browse the repository at this point in the history
There are tests for the CLI but these use click's `CliRunner` which
calls the commands directly from the Python API instead of calling the
actual CLI script. This would not catch if the script is not properly
installed or reachable. Here a test is added that tries to call the CLI
through a subprocess, which simulates the real situation of a user
invoking it.

This test would have caught the missing imports that were accidentally
removed by the `ruff` linter.
  • Loading branch information
sphuber committed Feb 26, 2024
1 parent f88feba commit 0743c3a
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/aiida_common_workflows/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
"""Module for the command line interface."""
from .launch import cmd_launch # noqa: F401
from .plot import cmd_plot # noqa: F401
from .root import cmd_root # noqa: F401
45 changes: 45 additions & 0 deletions tests/cli/test_root.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""Tests for CLI commands."""
from __future__ import annotations

import subprocess

import click
import pytest
from aiida_common_workflows.cli import cmd_root


def recurse_commands(command: click.Command, parents: list[str] | None = None):
"""Recursively return all subcommands that are part of ``command``.
:param command: The click command to start with.
:param parents: A list of strings that represent the parent commands leading up to the current command.
:returns: A list of strings denoting the full path to the current command.
"""
if isinstance(command, click.Group):
for command_name in command.commands:
subcommand = command.get_command(None, command_name)
if parents is not None:
subparents = [*parents, command.name]
else:
subparents = [command.name]
yield from recurse_commands(subcommand, subparents)

if parents is not None:
yield [*parents, command.name]
else:
yield [command.name]


@pytest.mark.parametrize('command', recurse_commands(cmd_root))
@pytest.mark.parametrize('help_option', ('--help', '-h'))
def test_commands_help_option(command, help_option):
"""Test the help options for all subcommands of the CLI.
The usage of ``subprocess.run`` is on purpose because using :meth:`click.Context.invoke`, which is used by the
``run_cli_command`` fixture that should usually be used in testing CLI commands, does not behave exactly the same
compared to a direct invocation on the command line. The invocation through ``invoke`` does not go through all the
parent commands and so might not get all the necessary initializations.
"""
result = subprocess.run([*command, help_option], check=False, capture_output=True, text=True)
assert result.returncode == 0, result.stderr
assert 'Usage:' in result.stdout

0 comments on commit 0743c3a

Please sign in to comment.