8

I am trying to use unittest with a program that uses the argparse module and having some difficulties. I referenced this helpful post as a starting point but I'm clearly still missing something.

Here is the basic program:

#arg_test.py
import sys
import argparse


class Thingy:
    def __init__(self, name):
        self.name = name

    def parse_args(args):
        parser = argparse.ArgumentParser(description='description here')
        parser.add_argument('-v', '--version', action='version', version='%(prog)s 0.1')
        parser.add_argument('-a', '--arg1', required=True, help='this is for arg1')
        parser.add_argument('-b', '--arg2', required=True, help='this is for arg2')
        return parser.parse_args()


def main():
    parser = Thingy.parse_args(sys.argv[1:])
    print('the args are: {}'.format(parser))
    if parser.arg1:
        print('the value of arg1 is : {}'.format(parser.arg1))
    if parser.arg2:
        print('the value of arg2 is : {}'.format(parser.arg2))


if __name__ == '__main__':
    main()

Running this:

python arg_test.py --arg1 asdf --arg2 qwer

Results in the expected output of:

the args are: Namespace(arg1='asdf', arg2='qwer')
the value of arg1 is : asdf
the value of arg2 is : qwer

Now here is the simple unittest program:

#test/test_arg_test.py
import unittest
from arg_test import Thingy


def test_parser(self):
    parser = Thingy.parse_args(['--arg1'])
    self.assertTrue(parser.arg1,'asdf')


if __name__ == '__main__':
    main()

Running this:

python -m unittest -v test/test_arg_test.py --arg1 asdf --arg2 qwer

Results in this:

python -m unittest -v test/test_arg_test.py --arg1 asdf --arg2 qwer
usage: python -m unittest [-h] [-v] [-q] [--locals] [-f] [-c] [-b]
                          [tests [tests ...]]
python -m unittest: error: unrecognized arguments: --arg1 asdf --arg2 qwer

Can someone please point me in the right direction on how to run these tests?

Thanks.

Update #1

Here is the updated unittest program based on the helpful recommendations below but something is still missing.

#import unittest
from arg_test import Thingy

class TestThingys(unittest.TestCase):
    def test_isupper(self):
        self.assertTrue('FOO'.isupper())
        self.assertFalse('Foo'.isupper())

    def test_parser(self):
        argv1 = ['--arg1', 'asdf', '--arg2', 'qwer']
        parser = Thingy().parse_args(argv1)
        self.assertTrue(parser.arg1,'asdf')

if __name__ == '__main__':
    main()

Running this:

python -m unittest -v test/test_arg_test.py

Results in this:

test_isupper (test.test_arg_test.TestThingys) ... ok
test_parser (test.test_arg_test.TestThingys) ... ERROR

======================================================================
ERROR: test_parser (test.test_arg_test.TestThingys)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/username/scripts/python/arg_test/test/test_arg_test.py", line 12, in test_parser
    parser = Thingy().parse_args(argv1)
TypeError: __init__() missing 1 required positional argument: 'name'

----------------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (errors=1)

Update #2

#test/test_arg_test.py
import unittest
from arg_test import Thingy

class TestThingys(unittest.TestCase):
    def test_isupper(self):
        self.assertTrue('FOO'.isupper())
        self.assertFalse('Foo'.isupper())

    def test_parser(self):
        argv1 = ['--arg1', 'asdf', '--arg2', 'qwer']
        parser = Thingy('name').parse_args(argv1)
        self.assertEquals(parser.arg1,'asdf')

if __name__ == '__main__':
    main()

Running this:

python -m unittest -v test/test_arg_test.py

Results in this:

test_isupper (test.test_arg_test.TestThingys) ... ok
test_parser (test.test_arg_test.TestThingys) ... ERROR

======================================================================
ERROR: test_parser (test.test_arg_test.TestThingys)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/username/scripts/python/arg_test/test/test_arg_test.py", line 12, in test_parser
    parser = Thingy('name').parse_args(argv1)
TypeError: parse_args() takes 1 positional argument but 2 were given

----------------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (errors=1)
user9074332
  • 2,336
  • 2
  • 23
  • 39
  • 1
    `unittest` runs its own parser that doesn't recognize your arguments. You are seeing its usage, not your's. – hpaulj Apr 15 '18 at 02:48
  • In addition, you already specified the arguments for the test *in* the test; you don't need to put them on the command line. – chepner Apr 15 '18 at 03:20
  • 2 changes needed, `Thingy()` to be `Thingy('name')`, and `self.assertTrue(parser.arg1,'asdf')` to be replaced with `self.assertEquals()` – Gang Apr 15 '18 at 17:51
  • It is not an answer to you question, but I think you should not test directly args parsing (assume it works, as it is standalone well tested module) and simply do not use it directly in your code. To stub args object use NamedTuple (or equivalent type) – R2RT Apr 15 '18 at 18:02
  • 2
    @R2RT, the reason to test is ensure the options has been used will not get changed without a warning. The purpose is not to test `argparse`. – Gang Apr 15 '18 at 18:35

1 Answers1

4

use argv inside class TestThingy

def test_parser(self):
    argv1 = ['--arg1', 'asdf', '--arg2', 'qwer']
    parser = Thingy('name').parse_args(argv1)
    self.assertEquals(parser.arg1,'asdf')

    argv2 = ['--trigger_exception`, 'asdf`]
    with self.assertRaise(Exception):
        parser = Thingy('name').parse_args(argv2)
ChrisGPT was on strike
  • 127,765
  • 105
  • 273
  • 257
Gang
  • 2,658
  • 3
  • 17
  • 38
  • Thanks for the feedback. I updated the code based on your recommendations, tested and put the results above, could you please have a look? – user9074332 Apr 15 '18 at 17:28
  • @user9074332, my mistake, I updated my code with the bug fixed, thanks – Gang Apr 15 '18 at 17:54