Search code examples
pythonpython-2.7python-unittestself-reference

Self reference for assertions while unittesting


First, assume the following directory structure of a Python package titled mypackage, which follows the instructions of the guide How To Package Your Python Code:

mypackage/
mypackage/mypackage/
mypackage/mypackage/__init__.py
mypackage/mypackage/a_function.py
mypackage/scripts/
mypackage/scripts/a_script.py
mypackage/tests/
mypackage/tests/a_function_test.py
mypackage/misc/
mypackage/misc/input.txt
# mypackage/misc/actual_output.txt  ## Not yet generated!
mypackage/misc/expected_output.txt
mypackage/setup.py

Second, assume that the script a_script.py imports a_function.py, reads the file input.txt, manipulates the content of input.txt and saves the latter as actual_output.txt into mypackage/misc/.

Third, assume that the unittest module mypackage/misc/ contains a test function to compare expected_output.txt to actual_output.txt via self.assertMultiLineEqual(expected, actual).

Finally, assume that I would like to run the unittest module via python2 setup.py test.

How do I specify the location of actual_output.txt and expected_output.txt in a_function_test.py without hardcoding their absolute filepaths (and, hence, preventing any transferability of my package)?

Consideration:

I can theoretically hardcode the within-package path to each of the two input files. However, how does the Python interpreter know where to look for mypackage if it is not yet installed to site-packages? I had the following idea, but it fails as mypackage is not yet known:

base_path = os.path.split(inspect.getfile(mypackage))[0]
within_path = mypackage/misc/
expected = open(base_path + within_path + expected_output.txt).read()
actual = open(base_path + within_path + actual_output.txt).read()
self.assertMultiLineEqual(expected, actual)

Solution

  • From a_script.py you can get to the main mypackage like so:

    mypackage_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    

    or:

    mypackage_dir = os.path.dirname(os.path.abspath(__package__))
    

    then, the other paths can be built, since you know the name of the subpackages:

    misc_dir = os.path.join(mypackage_dir, 'misc')
    tests_dir = os.path.join(mypackage_dir, 'tests')