How to test a Python program with command-line arguments in pytest
Recently I wanted to test how a Python program behaved with various combinations of command-line arguments.
Thanks to pytest's mocker fixture, this is easy to do:
def test_arguments_from_cli(mocker): """Test whether arguments from the command line are set up correctly in a HermesApp object.""" mocker.patch( "sys.argv", [ "rhasspy-hermes-app-test", "--host", "rhasspy.home", "--port", "8883", "--tls", "--username", "rhasspy-hermes-app", "--password", "test", ], ) app = HermesApp("Test arguments in init", mqtt_client=mocker.MagicMock()) assert app.args.host == "rhasspy.home" assert app.args.port == 8883 assert app.args.tls is True assert app.args.username == "rhasspy-hermes-app" assert app.args.password == "test"
You just patch the sys.argv variable with the command-line arguments you want to test your program with. This variable is a list of strings representing the arguments as separated by a space, and with the command's name as the first element. So this example function patches sys.argv
to behave as if the test function is running in a command you started as follows:
$ rhasspy-hermes-app-test --host rhasspy.home --port 8883 --tls --username rhasspy-hermes-app --password test
In this case the HermesApp object uses the argparse library to populate some attributes with values from sys.argv
, such as host
, port
, tls
, username
and password
. The function test_arguments_from_cli
tests whether these attributes are initialized correctly. But you can use the same approach if you have a main
function for your command that reads your command-line arguments.
If you want to test other combinations of command-line arguments, you just add another test function that patches sys.argv
with another list of arguments. All these test functions are executed independently with their own patched argument list.