click icon indicating copy to clipboard operation
click copied to clipboard

Enable CliRunner to echo output to stdout/stderr

Open OddBloke opened this issue 7 years ago • 2 comments

I'm driving my CliRunner testing from pytest. pytest will capture stdout/stderr by default, and display them when an assertion fails. As CliRunner captures all of the output itself, I don't get any guidance as to what my application has done on failure, without adding explicit debugging code to each assertion.

I'd like to be able to do something like CliRunner(echo=True) so that I get the output of its run both in its attributes and actually written to stdout/stderr.

OddBloke avatar Feb 16 '17 15:02 OddBloke

Would also love to see this.

I haven't dug deep into the internals for CliRunner.isolation() here, so I'm probably not doing this in the most correct way, but here's my workaround for anyone else interested:

import functools

import pytest


@pytest.fixture
def cli():
    """Yield a click.testing.CliRunner to invoke the CLI."""
    class_ = click.testing.CliRunner

    def invoke_wrapper(f):
        """Augment CliRunner.invoke to emit its output to stdout.

        This enables pytest to show the output in its logs on test
        failures.

        """
        @functools.wraps(f)
        def wrapper(*args, **kwargs):
            echo = kwargs.pop('echo', False)
            result = f(*args, **kwargs)

            if echo is True:
                sys.stdout.write(result.output)

            return result

        return wrapper

    class_.invoke = invoke_wrapper(class_.invoke)
    cli_runner = class_()

    yield cli_runner

...

def test_basic(cli, package):
    result = cli.invoke(package, ['--help])
    assert result.exit_code == 0

nguyening avatar Jun 17 '17 18:06 nguyening

I also came up against this. For the record my solution was the following helper method:

def invoke(cmd, expect_exit=0, catch_exceptions=False, **kwargs):
    runner = click.testing.CliRunner()
    result = runner.invoke(cli, cmd, catch_exceptions=catch_exceptions, **kwargs)
    if expect_exit is not None:
        assert result.exit_code == expect_exit
    return result

mbirtwell avatar Sep 15 '22 15:09 mbirtwell