Using Python's `unittest` module to compose tests of functions in a separate file

180 Views Asked by At

I have an issue with getting my unit tests to resolve calls to the S.U.T.'s functions. The S.U.T. is defined in a separate file, but in the same project. I've considerable Python experience, but I've never tried to deploy code in a conventional way (which generally suggests conventional testing). The directory structure I'm using seems to be in line with PyPI convention, but I'm missing the step on executing unit tests.

Note 1: I have tried reviewing the official unittest module's API documentation & tutorials, as well as some unofficial docs. There's not a lot bridging the gap between new, undeployed project and downloading projects already deployed.

Note 2: I'm not interested in using any third-party unit testing framework. I'd like to stick to unittest module and its conventions. I'm hoping to keep the original project as cross-platform and third-party dependency-light as possible.

Note 3: Adding import mfut or from mfut import conditionallyClose statements to all_tests.py results in ModuleNotFoundError: No module named 'mfut'. I'm sure this has something to do with the PYTHONPATH, but changing that environment variable strikes me as fragile. I'm hoping there's a more robust way.

Below is merely an example toy problem, but the test cases for the original project aren't much more sophisticated.


Given the following Python 3 project directory structure:

My Fun Unit Testing
    ├───src
    │   └───mfut
    │       └───mfut.py
    │
    └───tests
        └───all_tests.py

and the following contents of file mfut.py:

import math
def conditionallyClose(x1, x2):
    if math.abs(x1) < 1:
        return math.isclose(x1, x2)
    if math.abs(x1) < 1e6:
        return math.isclose(x1, x2, rel_tol=0.10)
    return math.isclose(x1, x2, rel_tol=0.001)

and the following contents of all_tests.py:

from unittest import TestCase
from math import inf
class onlyTestCase(TestCase):
    def testConditionallyClose_mag1(self):
        self.assertTrue(conditionallyClose(0.05, 0.06))

    def testConditionallyClose_mag6(self):
        self.assertTrue(conditionallyClose(1200000, 1085000))

    def testConditionallyClose_magInf(self):
        self.assertTrue(conditionallyClose(inf, inf))

what is the Python 3 convention (or requirement) for getting the conditionallyClose(...) calls in all_tests.py to resolve?

1

There are 1 best solutions below

3
Mohammad Alavi On

The reason for your error is that python cannot recognize any library with the name mfut. If you import it like this from mfut import conditionallyClose, it must be either a library, or a file in the same directory as your current python file.

To solve this problem, take these steps:

  1. First of all make sure that your project file structure is like this: enter image description here

  2. Create a setup.py file for you project (you can also use PyCharm to do it) and put it in the root directory of you project (which in this case is "B:\Repos\SampleProject").

  3. Activate your virtual environment and run pip install -e . in the root of you project directory. This will use the setup.py and make python run your code as a python library and refer to the code dynamically from your files.

  4. Now you can import your code like this from any file:

    from src.mfut.mfut import conditionallyClose