pythonpython-3.xunit-testingtestingpython-click

Testing argument using Python Click


I have a command-line script with Python-click with an argument and option:

# console.py
import click

@click.command()
@click.version_option()
@click.argument("filepath", type=click.Path(exists=True), default=".")
@click.option(
    "-m",
    "--max-size",
    type=int,
    help="Max size in megabytes.",
    default=20,
    show_default=True,
)
def main(filepath: str, max_size: int) -> None:
    max_size_bytes = max_size * 1024 * 1024  # convert to MB
    if filepath.endswith(".pdf"):
        print("success")
    else:
        print(max_size_bytes)

Both the argument and option have default values and work on the command-line and using the CLI it behaves as expected. But when I try testing it following Click documentation and debug it, it does not enter the first line:

# test_console.py
from unittest.mock import Mock

import click.testing
import pytest
from pytest_mock import MockFixture

from pdf_split_tool import console

@pytest.fixture
def runner() -> click.testing.CliRunner:
    """Fixture for invoking command-line interfaces."""
    return click.testing.CliRunner()

@pytest.fixture
def mock_pdf_splitter_pdfsplitter(mocker: MockFixture) -> Mock:
    """Fixture for mocking pdf_splitter.PdfSplitter."""
    return mocker.patch("pdf_split_tool.pdf_splitter.PdfSplitter", autospec=True)

def test_main_uses_specified_filepath(
    runner: click.testing.CliRunner,
    mock_pdf_splitter_pdfsplitter: Mock, 
) -> None:
    """It uses the specified filepath."""
    result = runner.invoke(console.main, ["test.pdf"])
    assert result.exit_code == 0

I couldn't see why it is giving since the debugger did not enter the first line of function main(). Any ideas of what could be wrong?


Solution

  • The failure is due to following error.

    (pdb)print result.output
    "Usage: main [OPTIONS] [FILEPATH]\nTry 'main --help' for help.\n\nError: Invalid value for '[FILEPATH]': Path 'test.pdf' does not exist.\n"
    

    This is happening due to following code in console.py which checks if the filepath exists. @click.argument("filepath", type=click.Path(exists=True), default=".")

    One way to test creating a temporary file is using afterburner's code:

    # test_console.py
    def test_main_uses_specified_filepath() -> None:
        runner = click.testing.CliRunner()
        with runner.isolated_filesystem():
            with open('test.pdf', 'w') as f:
                f.write('Hello World!')
    
            result = runner.invoke(main, ["test.pdf"])
        assert result.exit_code == 0