i am currently working on a project, where i need to run tests inside a different file structure like this:
/my_project
├── __init__.py
├── ...my python code
/given_proj
├── __init__.py
├── /package
│ ├── __init__.py
│ └── main.py
└── /tests
└── test_main.py
From inside my project i want to execute the tests within the given project.
My current approach is using unittest.TextTestRunner like this:
unittest.TextTestRunner().run(unittest.defaultTestLoader.discover('../given_proj/tests'))
.
Of course the test file wants to import from main.py
like this from package.main import my_function
. However when i run my code, the tests fail to run because the "package" module cannot be found:
...\given_proj\tests\test_main.py", line 2, in <module>
from package.main import my_function
ModuleNotFoundError: No module named 'package'
When i run the tests with python -m unittest discover -s tests
from the command line in the directory of the given_proj
they run fine.
I tried changing the working directory to given_proj
with os.chdir('../given_proj')
however it produces the same result.
What i kinda tried, was importing the module manually with importlib.import_module()
. There i am not sure if i did it wrong or it doesnt work either.
How do i make it, that the tests get run, as if i would run it from the actual directory they are supposed to run? Ideally i wouln't need to change the "given_project" at all, because i want to do this with multiple projects.
I reduced it to a very minimal project, if anybody wants to try and reproduce it. The file-structure is the one at the top of the post.
All __init__.py
files are empty.
/my_project/main.py
:
import os
import unittest
import os
import unittest
if __name__ == "__main__":
dirname = "../given_proj/tests" #either "./" or "../" depending of where you run the python file from
unittest.TextTestRunner().run(unittest.defaultTestLoader.discover(dirname))
/given_proj/package/main.py
:
def my_function(num):
return num*2
/given_proj/tests/test_main.py
:
import unittest
from package.main import my_function
class TestMain(unittest.TestCase):
def test_my_function(self):
result = my_function(5)
self.assertEqual(result, 10)
result = my_function(10)
self.assertEqual(result, 20)
result = my_function(0)
self.assertEqual(result, 0)
if __name__ == '__main__':
unittest.main()
A possible solution is to add the following instructions in your file test_main.py
:
import unittest
import sys # <-- add this import
sys.path.insert(1, '..') # <-- add this instruction
print(sys.path) # <--- TO CHECK THE CONTENT OF sys.path
#from package.main import my_function # <--- comment your import
from given_proj.package.main import my_function # <--- add this import
class TestMain(unittest.TestCase):
def test_my_function(self):
result = my_function(5)
self.assertEqual(result, 10)
result = my_function(10)
self.assertEqual(result, 20)
result = my_function(0)
self.assertEqual(result, 0)
if __name__ == '__main__':
unittest.main()
If I execute test method test_my_function()
on my system it passes.
The instruction sys.path.insert(1, '..')
add a path where the test code search package
.
If I change directory to the folder given_proj
and execute the following command:
> cd /path/to/given_proj
/path/to/given_proj> python tests/test_main.py
The output of the execution is the following:
['/path/to/given_proj/tests', '..', '/other/paths']
.
Ran 1 test in 0.000s
OK
In the output you can see the print of the content of sys.path
.