Python: Writing test to verify command line arguments

Python: Writing test to verify command line arguments

I wrote a small Python script that will be executed from the command line. After finishing the tests to verify the business logic, I decided to test the command line arguments as well, just to make sure they’re parsed correctly and passed to their appropriate places in the business logic code.

Initially I was thinking I needed to write a test that executes the actual command line such as python3 myscript.py --argument=value, but as this is neither appropriate nor really necessary for my testing needs, I decided to refactor the production code somewhat to make it testable. More precisely, instead of placing code in inside the if __name__ == '__main__' block, I decided to refactor the code to look like this:

class Deployer:
   <snip>

def parse_arguments(args):
    <snip>

def main(args):
    arguments = parse_arguments(args)
    config_file_path = arguments["config_file_path"]
    destination_environment = arguments["destination_environment"]
    version = arguments["version"]
    application_name = arguments["application"]

    deployer = Deployer(config_file_path=config_file_path,
                        application_name=application_name,
                        destination_environment=destination_environment,
                        version=version)
    deployer.deploy()


if __name__ == '__main__':
    main(sys.argv[1:])

Notice that the main(args) function take care of verifying the script’s arguments, and initialized and start the business logic inside the “Deployer” class.

By placing this initial part of the script’s functionality inside the main(args) function, it’s much easier to test:

import deploy

<snip>

@mock.patch("deploy.Deployer", autospec=True)
    def test_that_command_line_arguments_are_parsed_correctly(self, mocked_deployer):
        config_file_path = "/path/to/config.json"
        application_name = "myapp"
        destination_environment = "production"
        version = "1.0.0"

        args_as_string = "--application=" + application_name + \
                         " --config-file-path=" + config_file_path + \
                         " --destination-environment=" + destination_environment + \
                         " --version=" + version

        args = args_as_string.split(" ")  # This is how sys.argv[1:] passes arguments

        deploy.main(args=args)

        mocked_deployer.assert_called_once_with(config_file_path=config_file_path,
                                                application_name=application_name,
                                                destination_environment=destination_environment,
                                                version=version)

        mocked_deployer.return_value.deploy.assert_called_once()

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: