0

Recently, I've discovered that modules are singleton in Python. And it's nice, because in some cases, this pattern is useful.

Personally, I like to use it in modules that are shared everywhere, like the options.

For example, here's a very simple options module using argparse :

#options.py
import argparse

parser = argparse.ArgumentParser(prog='myoptions')
parser.add_argument('-c', action='store')
options = parser.parse_args()

Whenever I import options, the code is executed once and the variable options contains all the options parsed. Wonderful !

Except that now, I want to test this. But the way I coded it makes it very hard to test it:

  • When I import the module in my test file, argparse tries to parse the argv, and it failed, as the argv is the one from unittest
  • as it's loaded and executed only once, I can test only one part of the options module. Importing options multiple time doesn't work.

I can work around this issue pretty quickly by wrapping the parse_args call in a function and calling this function in each unit test. But then, in my "real" code, whenever I'll need an option, I will have to import options module, then execute the "wrap function", that will parse the arguments and give me the options.

It's doable, but it's not pretty, because:

  • I will have to import + call the "parse" function in any module that needs an option
  • It will execute the parsing of argv every time while normally, it should be executed once.

So, how can I make this code both unit-testable and easy to use ?

Thanks for your help !

sterfield
  • 71
  • 4
  • Possible duplicate of [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) – TemporalWolf Feb 03 '17 at 22:40
  • I'm sorry, but that's not a duplicate, at least not directly. If you change sys.argv, it will work but only for one test, as the code is imported / executed once. I know it because I tried it :) – sterfield Feb 04 '17 at 09:32

1 Answers1

0

After a bit of research, it seems that there's no obvious solution to this situation.

Among all the possibilities, I've decided to put a small if around the parsing of the variables :

if os.environ.get('UNITTEST', 0):
    options = None
else:
    options = _parser.parse_args()

Then, I feed a env vars UNITTEST=1 in the unittest file and do the parsing in the unit test function. That allows me to feed manually parse_args to test my options and when the program is executed, the options are parsed immediately.

sterfield
  • 71
  • 4