Search code examples
pythonpython-unittestargs

Correct class structure for arg parse, for unittests


My script:

class Pivot:
    def __init__(self):
        self.args = self.parse_args()

        self.path = os.getcwd()
        self.file = self.args.filename

        if self.args.delimiter:
            self.delimiter = self.args.delimiter
        else:
            self.delimiter = ";"


    def parse_args(self):
        parser = argparse.ArgumentParser(prog="TBD",
                                     description="TBD")

        parser.add_argument("-f", "--filename", help="blahblah")
        parser.add_argument("-d", "--delimiter", help="blahblah")
        args = parser.parse_args()

        return args

if __name__ == "__main__":
    p = Pivot()

And my current test.py:

class TestPivot(unittest.TestCase):
    def setUp(self):
        self.pivot = Pivot()

    def tearDown(self):
        pass

    
    def test_parse_args(self):
        parsed = self.parser.parse_args(['-f', 'test'])
        self.assertEqual(parsed.something, 'test')


    def test_minimal(self):
        """To make sure at least a test is passed"""
        self.assertEqual("neo".upper(), "NEO")

Then when I run python3 -m unittest tests/test_Pivot.py, I get:

E
usage: Pivot table representation [-h] [-f FILENAME] [-d DELIMITER]
Pivot table representation: error: unrecognized arguments: tests/test_Pivot.py
E
======================================================================
ERROR: test_create_pivot (tests.test_Pivot.Pivot)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Project/tests/test_Pivot.py", line 21, in setUp
    self.pivot = Pivot()
  File "/Project/Pivot.py", line 25, in __init__
    self.args = self.parse_args()
  File "/Project/Pivot.py", line 42, in parse_args
    args = parser.parse_args()

Should my class be restructured differently when dealing with argparse, and if so, how? At present I can't even get the simple tests to run, because of how the class is being instantiated.


Solution

  • Thanks for the suggestion (@MrBean Bremen), I refactored my code, so that the parse_args now lies outside of my class:

    def parse_args(args):
        parser = argparse.ArgumentParser(prog="blah",
                                         description="blah")
    
        parser.add_argument("-f", "--filename", help="blah")
        parser.add_argument("-d", "--delimiter", help="blah")
    
        return parser.parse_args(args)
    
    class Pivot:
        def __init__(self, args):
            self.path = os.getcwd()
            self.file = args.filename
    
            if args.delimiter:
                self.delimiter = args.delimiter
            else:
                self.delimiter = ";"
    
    
    if __name__ == "__main__":
        args = parse_args(sys.argv[1:])
        p = Pivot(args)
    

    Then my tests become:

    class TestPivot(unittest.TestCase):
        def setUp(self):
            args = parse_args(["-f", "test1", "-d", ","])
            self.pivot = Pivot(args)
    
        def test_init(self):
            self.assertEqual(self.pivot.file, "test1")
            self.assertEqual(self.pivot.delimiter, ",")
    
        def test_parse_args(self):
            parsed = parse_args(["-f", "test2"])
            self.assertEqual(parsed.filename, "test2")
            self.assertNotEqual(parsed.filename, "test3")