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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With