The best solution in my opinion is to use the unittest command line interface which will add the directory to the sys.path so you don't have to (done in the TestLoader class).
For example for a directory structure like this:
new_project
βββ antigravity.py
βββ test_antigravity.py
You can just run:
$ cd new_project
$ python -m unittest test_antigravity
For a directory structure like yours:
new_project
βββ antigravity
β βββ __init__.py # make it a package
β βββ antigravity.py
βββ test
βββ __init__.py # also make test a package
βββ test_antigravity.py
And in the test modules inside the test package, you can import the antigravity package and its modules as usual:
# import the package
import antigravity
# import the antigravity module
from antigravity import antigravity
# or an object inside the antigravity module
from antigravity.antigravity import my_object
Running a single test module:
To run a single test module, in this case test_antigravity.py:
$ cd new_project
$ python -m unittest test.test_antigravity
Just reference the test module the same way you import it.
Running a single test case or test method:
Also you can run a single TestCase or a single test method:
$ python -m unittest test.test_antigravity.GravityTestCase
$ python -m unittest test.test_antigravity.GravityTestCase.test_method
Running all tests:
You can also use test discovery which will discover and run all the tests for you, they must be modules or packages named test*.py (can be changed with the -p, --pattern flag):
$ cd new_project
$ python -m unittest discover
$ # Also works without discover for Python 3
$ # as suggested by @Burrito in the comments
$ python -m unittest
This will run all the test*.py modules inside the test package.
Here you can find the updated official documentation of discovery.
The best solution in my opinion is to use the unittest command line interface which will add the directory to the sys.path so you don't have to (done in the TestLoader class).
For example for a directory structure like this:
new_project
βββ antigravity.py
βββ test_antigravity.py
You can just run:
$ cd new_project
$ python -m unittest test_antigravity
For a directory structure like yours:
new_project
βββ antigravity
β βββ __init__.py # make it a package
β βββ antigravity.py
βββ test
βββ __init__.py # also make test a package
βββ test_antigravity.py
And in the test modules inside the test package, you can import the antigravity package and its modules as usual:
# import the package
import antigravity
# import the antigravity module
from antigravity import antigravity
# or an object inside the antigravity module
from antigravity.antigravity import my_object
Running a single test module:
To run a single test module, in this case test_antigravity.py:
$ cd new_project
$ python -m unittest test.test_antigravity
Just reference the test module the same way you import it.
Running a single test case or test method:
Also you can run a single TestCase or a single test method:
$ python -m unittest test.test_antigravity.GravityTestCase
$ python -m unittest test.test_antigravity.GravityTestCase.test_method
Running all tests:
You can also use test discovery which will discover and run all the tests for you, they must be modules or packages named test*.py (can be changed with the -p, --pattern flag):
$ cd new_project
$ python -m unittest discover
$ # Also works without discover for Python 3
$ # as suggested by @Burrito in the comments
$ python -m unittest
This will run all the test*.py modules inside the test package.
Here you can find the updated official documentation of discovery.
I've had the same problem for a long time. What I recently chose is the following directory structure:
project_path
βββ Makefile
βββ src
β βββ script_1.py
β βββ script_2.py
β βββ script_3.py
βββ tests
βββ __init__.py
βββ test_script_1.py
βββ test_script_2.py
βββ test_script_3.py
and in the __init__.py script of the test folder, I write the following:
import os
import sys
PROJECT_PATH = os.getcwd()
SOURCE_PATH = os.path.join(
PROJECT_PATH,"src"
)
sys.path.append(SOURCE_PATH)
Super important for sharing the project is the Makefile, because it enforces running the scripts properly. Here is the command that I put in the Makefile:
run_tests:
python -m unittest discover .
The Makefile is important not just because of the command it runs but also because of where it runs it from. If you would cd in tests and do python -m unittest discover ., it wouldn't work because the init script in unit_tests calls os.getcwd(), which would then point to the incorrect absolute path (that would be appended to sys.path and you would be missing your source folder). The scripts would run since discover finds all the tests, but they wouldn't run properly. So the Makefile is there to avoid having to remember this issue.
I really like this approach because I don't have to touch my src folder, my unit tests or my environment variables and everything runs smoothly.
python - unittest directory structure - cannot import src code - Stack Overflow
unit testing - Separate src and test directories with Python - Stack Overflow
How to import project source code from the test folder with unittest ?
How to generate unit tests for Python using src and test folder structure (preferable with PyCharm integration)? - Stack Overflow
Hi all !
I have a very classic projet with 2 folders :
src (which contains my source files) test (which contains unit tests of my source code)
I would like my test folder to import modules from src folder to test them. But my problem is that I had to modify sys.path in each file of my test folder to make it work. Indeed I don't think it's a good technique because it entails a lot of code duplication and a lot of modification if I decide to change the arborescence in my test folder.
I feel like the right technique (don't hesitate to correct me if I'm wrong) would be to modify sys.path in one file only for the entire test folder. The problem is that my test folder contains a lot of subfolders and sub-subfolders. I tried to use relative import to import the source modules in my test files but I get this fairly classical Python error :
ImportError: attempted relative import with no known parent package
Anyone knows how to have a test folder outside the actual source code ? I've seen dozens of project that put the test folder outside the source code like me but I didn't find anything similar enough to my case to get inspiration (a project which uses unittest and which organize the code in several subfolders and sub-subfolders).
Thx in advance !
A very wrong thing to do is appending a relative path to sys.path.
If you want to be sure about the path, make it as follows:
# assuming that the code is in test's __init__.py
import os
import sys
sys.path.insert(0, os.path.abspath( os.path.join(os.path.dirname(__file__),
'../src/') ))
# now you can be sure that the project_root_dir/src comes first in sys.path
I think you got it almost right. But as you run your tests form the root directory, your path ('../src') is wrong I guess. Maybe you can do something like this:
import os
import sys
ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..')
sys.path.append(os.path.join(ROOT, 'src'))
from cmds.baz import about
The Python Packaging Authority recommends separating the test directory from the src (source code) directory in a Python application:
https://packaging.python.org/en/latest/tutorials/packaging-projects/#creating-the-package-files
Personally, I have always preferred this approach of keeping tests outside the package rather than mixing them with the source code (tests in package).
However, in the interest of expanding my perspective and learning something new, I am open to exploring alternative viewpoints. What are the main arguments for including tests within the package itself?
Image taken from https://blog.ionelmc.ro/2014/05/25/python-packaging/Disclaimer: I initially posted this on r/learnprogramming but no one was responding, so I deleted that post and I'm posting this here. I also tried some googling (which I had tried prior to writing the post) and found both this post on r/learnpython and this post on StackOverflow. However, both speak about importing a Python file or module from the parent directory of there the Python test file is. I'm trying to do something a little different, although perhaps one of the answers given in those two posts would still apply. Anyway, here's my original post.
I'm using Python's unittest module to test my program. This is my first time using unittest. Currently I have my program py file in the same folder as the test py file. But I want to move them both into their own subfolders. As an example, this is my current setup:
\ root | |- my_program.py <- The program file | |- test.py <- The unittest file
In test.py, my code looks similar to the following:
import unittest
import my_program
class TestMyProgram(unittest.TestCase):
@classmethod
def setupClass(cls):
cls.PROGRAM = my_program
def test_method_one(self):
expected_result = "Some result"
self.assertEqual(self.PROGRAM.method_one(),expected_result)
if __name__ == "__main__":
unittest.main()As I mentioned though, I would like to reorganize my directory structure to the following:
\ root | |-- program_files <- directory |--| |--|- my_program.py | |-- tests <- directory |--| |--|- test.py
However, if I do that, what should my import statement look like to access my_program.py? Would it work if I used import package.module.pyfile? So, continuing my example above and using root as the project name, I would have something like import root.program_files.my_program. If it makes a difference, I'm using VS Code and running the test.py file using VS Code's run button.
You could add that directory to the path:
import sys
sys.path.append('../src')
Maybe put this into a module if you are using it a lot.
Although this solution works for some situations, there are better solutions. See for example this answer.
If you don't want to add the source path to each test file or change your PYTHONPATH, you can use nose to run the tests.
Suppose your directory structure is like this:
project
package
__init__.py
module.py
tests
__init__.py
test_module.py
You should import the module normally in the test_module.py (e.g. from package import module). Then run the tests by running nosetests in the project folder. You can also run specific tests by doing nosetests tests/test_module.py.
The __init__.py in the tests directory is necessary if you want to run the tests from inside it.
You can install nose easily with easy_install or pip:
easy_install nose
or
pip install nose
nose extends unittest in a lot more ways, to learn more about it you can check their website: https://nose.readthedocs.org/en/latest/
There is a os function to change the directory, try adding os.chdir('src') to your test.
import unittest
import os
from src.main import get_cwd
class TestMain(unittest.TestCase):
def test_get_cwd(self):
os.chdir('src')
print('testing get_cwd()')
current_dir = get_cwd()
self.assertIsNotNone(current_dir)
self.assertEqual(current_dir, 'src')
An option is to mock the value given by os.path.basename with a return value of "src"
import unittest
from mock import patch
from src.main import get_cwd
class TestMain(unittest.TestCase):
@patch('os.path.basename')
def test_get_cwd(self, basename):
basename.return_value = "src"
print('testing get_cwd()')
current_dir = get_cwd()
self.assertIsNotNone(current_dir)
self.assertEqual(current_dir, 'src')
If you're using py.test to run the tests, it won't find the application as you must have not installed it. You can use python -m pytest to run your tests, as python will auto-add your current working directory to your PATH.
Hence, using python -m pytest .. would work if you're doing it in the src directory
The structure that I normally use is:
root
βββ packagename
β βββ __init__.py
β βββ ...
βββ tests
βββ ...
This way when I simply run python -m pytest in the root directory it works fine. Read more at: https://stackoverflow.com/a/34140498/1755083
Second option, if you still want to run this with py.test you can use:
PYTHONPATH=src/ py.test
and run it from the root. This simply adds the src folder to your PYTHONPATH and now your tests will know where to find the packagename package.
The third option is to use pip with -e to install your package in the editable mode. This creates a link to the packagename folder and installs it with pip - so any modification done in packagename is immediately reflected in pip's installation (as it is a link). The issue with this is that you need to redo the installation if you move the repo and need to keep track of which one is installed if you have more than 1 clones/packages.
Your layout looks OK and is the today recommended.
But I assume your problem are the import in your test_*.py files. You shouldn't take care about from where to import your package in you unittests; just import them.
Install in Development Mode via --editable
How could this be done? You have to "install" your package in Developement Mode. Use the --editable option of pip. In that case not a real package is build and installed but only symlinks are used to expose your package folder (the source in developer version) to the operating system as it would be a real release package.
Now your unittest never need to care about where the package is installed and how to import it. Just import it because the package is known to the system.
Note: This is the today recommended way. Other "solutions" hacking around with manipulating sys.path or environment variables like PYTHONPATH are just from Python's early days and should be avoided today.