How do I use CliRunner to test a script?
Asked Answered
D

3

6

I have a script that uses click to get input arguments. According to their documentation CliRunner can be used to make unit testing:

import click
from click.testing import CliRunner

def test_hello_world():
    @click.command()
    @click.argument('name')
    def hello(name):
        click.echo('Hello %s!' % name)

    runner = CliRunner()
    result = runner.invoke(hello, ['Peter'])
    assert result.exit_code == 0
    assert result.output == 'Hello Peter!\n'

This is done for a tiny hello-world function that is written in-line in the test. My queation is:

How do I perform the same test for a script in a different file??

Example of script that uses click:

import click
@click.command()
@click.option('--count', default=1, help='Number of greetings.')
@click.option('--name', prompt='Your name', help='The person to greet.')
def hello(count, name):
    """Simple program that greets NAME for a total of COUNT times."""
    for x in range(count):
        click.echo('Hello %s!' % name)

if __name__ == '__main__':
    hello()

(from click documentation)

EDIT:

If I try to run it as suggested in Dan's answer, after a couple of hours it shows this error:

test_hello_world (__main__.TestRasterCalc) ... ERROR

======================================================================
ERROR: test_hello_world (__main__.TestRasterCalc)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/src/HelloClickUnitTest.py", line 35, in test_hello_world
    result = runner.invoke(hello, ['Peter'])
  File "/usr/local/lib/python2.7/dist-packages/click/testing.py", line 299, in invoke
    output = out.getvalue()
MemoryError

----------------------------------------------------------------------
Ran 1 test in 9385.931s

FAILED (errors=1)
Dysart answered 21/7, 2017 at 10:14 Comment(0)
B
3

Your testing has a couple of challenges.

  1. Your program expects the name to be specified as an option via --name.

    To fix the test, pass ['--name', 'Peter'] to invoke().

  2. Additionally, if the option is not specified, then is is prompted for. The MemoryError is due to click constantly trying to prompt the non-existent user.

    To fix the test, pass input='Peter\n' to invoke. This will act as if the user typed: Peter at the prompt.

Code:

import click
from click.testing import CliRunner


@click.command()
@click.option('--count', default=1, help='Number of greetings.')
@click.option('--name', prompt='Your name', help='The person to greet.')
def hello(count, name):
    """Simple program that greets NAME for a total of COUNT times."""
    for x in range(count):
        click.echo('Hello %s!' % name)


def test_hello_world():

    runner = CliRunner()
    result = runner.invoke(hello, ['--name', 'Peter'])
    assert result.exit_code == 0
    assert result.output == 'Hello Peter!\n'

    result = runner.invoke(hello, [], input='Peter\n')
    assert result.exit_code == 0
    assert result.output == 'Your name: Peter\nHello Peter!\n'

test_hello_world()
Babettebabeuf answered 6/5, 2018 at 23:21 Comment(0)
W
2

I struggled on this for ages as well. Turns out the answer is simpler than you think. It all lies in the runner.invoke() function. In your case:

runner.invoke(hello, '--count 3 --name Peter')
Wallop answered 26/2, 2020 at 10:42 Comment(0)
L
0

In your test file do something like this.

import click
from click.testing import CliRunner
from hello_module import hello  # Import the function to test

    def test_hello_world():
        runner = CliRunner()
        result = runner.invoke(hello, ['Peter'])
        assert result.exit_code == 0
        assert result.output == 'Hello Peter!\n'
Leghorn answered 21/7, 2017 at 18:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.