2

I am writing a unit test for the following function which is in my_script.py:

def _parse_args():
    parser = argparse.ArgumentParser(
        description='Script to configure appliance.'
    )
    parser.add_argument('--config_file',
                        help='Path to a JSON configuration file') 
    print parser.parse_args()
    return parser.parse_args()

I want to create a unit test to mimic the command line prompt:

myscript.py --config_file test.json

This is what I have so far:

def test_parse_arg_test_config(self):

        test ={
                "name": "test_name",
                "category": "test_category"
            }

        # set the fake command line prompt to be:
        # myscript.py --config_file test
        # (where test is defined above)

        self.assertEquals(my_script._parse_args().config_file, test)

It is obviously incomplete, but I was wondering if I am approaching this the correct way since _parse_args doesn't take in any inputs I don't know a different way to mimic a config file being passed into the function.

Catherine
  • 727
  • 2
  • 11
  • 30
  • What you should do is mock ArgumentParser, so you get `parse_args` to return the data structure you want to use to test your code. The [Mock](http://www.voidspace.org.uk/python/mock/getting-started.html) documentation is pretty good, and there are several examples out there that will help you. – idjaw Mar 31 '16 at 12:35
  • I believe you can do `parser.parse_args(["my_script.py", "--config_file", "test"])` – zondo Mar 31 '16 at 12:39
  • @zondo I have tried that but the _parse_args function does not take in any arguments itself. This produces the following error "TypeError: _parse_args() takes no arguments (1 given)" – Catherine Mar 31 '16 at 12:46
  • @Catherine When it comes to unittesting, you *should* really look in to mock for things like this. – idjaw Mar 31 '16 at 12:52
  • Did you try assigning directly to `sys.argv`? `sys.argv = ["my_script.py", "--config_file", "test"]` – cdarke Mar 31 '16 at 12:55
  • @Catherine Look at [this](http://stackoverflow.com/questions/18160078/how-do-you-write-tests-for-the-argparse-portion-of-a-python-module) and [this](http://stackoverflow.com/questions/32393206/test-argparse-with-unittest-and-mock). Those are really good examples. One uses mock, and the other does not. Should be a good example so you can choose which direction you want to go in . – idjaw Mar 31 '16 at 12:55
  • And here is another mock [example](http://rallion.bitbucket.org/explorations/mock/standard_library/mock_argparse.html) – idjaw Mar 31 '16 at 12:57
  • @idjaw I have previously tried to create a mock Argument parser but it wasn't working for me correctly so I was trying a different approach. I will continue to look into it but also curious about other options – Catherine Mar 31 '16 at 12:59
  • @Catherine I'm curious to see your code attempt at mocking. Or you can maybe even compare what you tried with the examples I showed. If you can post your code, I (or someone else) can further assist in guiding you to see where you made a mistake. Mock + unittest are great tools to put together powerful unittests. – idjaw Mar 31 '16 at 13:00

1 Answers1

2

To pass args into the function add argument args

def _parse_args(args):
    parser = argparse.ArgumentParser(
        description='Script to configure appliance.'
    )
    parser.add_argument('--config_file',
                        help='Path to a JSON configuration file') 
    print parser.parse_args(args)
    return parser.parse_args(args)

Now you can call it this way:

self.assertEquals(my_script._parse_args(["--config_file", "test"]).config_file,"test")
Dmitry
  • 2,626
  • 2
  • 10
  • 15
  • Thank you very much! This works but I was wondering do you know why if I remove the quotation marks around test it fails, even though I have specified test? – Catherine Mar 31 '16 at 13:06
  • argparse is the Parser for command-line options, arguments and sub-commands. It is not for parsing files, specified in arguments. – Dmitry Mar 31 '16 at 13:11
  • It just reads the string `--config_file test.json` and creates a Namespace object that is easy to use and contains name of the config_file. If you want to see what's in the test.json, you have to read the file first: `import json json.load(my_script._parse_args(["--config_file", "test"]).config_file)` and than you can compare it with the test without quotes – Dmitry Mar 31 '16 at 13:27