2

I want to write unit tests for a Python script. The script itself runs correctly.

The script consists of one class, which reads a value from the command line into a class variable.

When I import the class into my test file, I get the error 'list index out of range' at the point where the class reads from sys.argv[].

I'm new to testing, in Python and in general. I've read a lot of doc and SO pages about this over the last couple of days.

Here's the code:

File bongo.py --

import sys

class Bongo:

    my_int = int(sys.argv[1])

    def __init__(self, n):
        self.n = n

    def get_sum(self):
        return self.n + Bongo.my_int

if __name__ == '__main__':
    bongo = Bongo(5)
    m = bongo.get_sum()
    print('bongo.get_sum() returns {}'.format(m))

File bongo_test.py --

import unittest
from bongo import Bongo

class TestBongoMethods(unittest.TestCase):

    def setUp(self):
        self.bongo = Bongo(10)
        self.bongo.my_int = 5

    def test_get_n(self):
        self.assertEqual(self.bongo.get_sum(), 15)

if __name__ == '__main__':
    unittest.main()

The output of running python bongo_test.py is

Traceback (most recent call last):
  File "bongo_test.py", line 2, in <module>
    from bongo import Bongo
  File "/home/me/class_for_testing/bongo.py", line 4, in <module>
    class Bongo:
  File "/home/me/class_for_testing/bongo.py", line 6, in Bongo
    my_int = int(sys.argv[1])
IndexError: list index out of range

I've tried just about everything I can think of; I've been using Py 2.7 in PyCharm Pro 2016.1, but the results are no different using Py 3.4 or running from the command line.

Can this be done using unittest? Or do I need something else?

Any help would be much appreciated!

codeforester
  • 39,467
  • 16
  • 112
  • 140
jazcap53
  • 381
  • 5
  • 17
  • 1
    I think this is quite related: [How do I set sys.argv so I can unit test it?](http://stackoverflow.com/questions/18668947/how-do-i-set-sys-argv-so-i-can-unit-test-it) – alecxe Jul 05 '16 at 15:08

2 Answers2

2

Generally, unit testing is helpful in figuring out the boundaries of your classes. If your class is hard to unit test, you should think: "how can I make it easier to test?" Almost always this leads to better structured classes.

One of these symptoms is that you have external dependencies, like sys.argv, that are hard to control. Generally you want to inject dependencies like this into a class. This is one of the advantages of object-oriented programming -- that you can isolate dependencies and minimize the complexity of the objects themselves.

The __main__ block is perfect for command-line specific logic, like sys.argv. I would recommend reading the variable there, and passing it into the constructor of Bongo. Then you can unittest Bongo as a class that takes two variables, and have it be ignorant of sys.argv.

szxk
  • 1,769
  • 18
  • 35
1

For command line args I suggest you argparse package (included in plain Python.)

The __main__ part will contain parsing by and the call of the main method.

You will can test separately both:

  • arg parsing
  • business logic with given parameters
AS Mackay
  • 2,831
  • 9
  • 19
  • 25
Claudio
  • 3,060
  • 10
  • 17