234 words
1 minute
Writing pytest tests against tools written with argparse

Writing pytest tests against tools written with argparse#

I usually build command-line tools using Click (and my click-app cookiecutter template), which includes a really nice set of tools for writing tests.

Today I decided to try building a tool called stream-delay using argparse from the Python standard library, since it didn’t need any other dependencies.

The one challenge I had was how to write the tests. I used pytest as a test-only dependency.

Here’s the pattern I came up with, using the capsys pytest fixture to capture standard output from my tool.

from stream_delay import main
import pytest
@pytest.mark.parametrize("option", ("-h", "--help"))
def test_help(capsys, option):
try:
main([option])
except SystemExit:
pass
output = capsys.readouterr().out
assert "Stream one or more files with a delay" in output

My main() function starts like this:

import argparse, sys
parser = argparse.ArgumentParser(
description="Stream one or more files with a delay between each line"
)
parser.add_argument("files", type=argparse.FileType("r"), nargs="*", default=["-"])
parser.add_argument("-d", "--delay-in-ms", type=int, default=100)
def main(args=None):
parsed_args = parser.parse_args(args)
delay_in_s = float(parsed_args.delay_in_ms) / 1000
# ...

As you can see, main() takes an optional list of arguments. The default for that is None which will cause argparse to read sys.argv - but I can inject arguments to the function from my tests if I need to.

I’m catching the SystemExit exception because this will be raised by default if you use -h or --help - but I still want to finish my test execution so I can inspect the captured output.

Complete code:

Writing pytest tests against tools written with argparse
https://mranv.pages.dev/posts/writing-pytest-tests-against-tools-written-with-argparse/
Author
Anubhav Gain
Published at
2024-07-18
License
CC BY-NC-SA 4.0