I have a directory structure as follows:
DirA
__init__.py
MyClass.py
unittests <------------------directory
MyClassTest.py
MyClassTest.py is executable:
import unittest
from . import MyClass
class MyClassTestCase(unittest.TestCase):
""" Testcase """
...
.....
if __name__ == '__main__':
unittest.main()
I get an error "Parent module '' not loaded, cannot perform relative import" at the line:
from . import MyClass
I would like to place unittests in a 'unittests' directory beside the modules being tested. Is there a way to do this and have access to all the modules in the parent directory which I am testing?
Have you tried running the tests like so:
cd DirA
python -m unittest discover unittests "*Test.py"
This should find your modules correctly. See Test Discovery
Use whatever layout you want, depending on your own preferences and the way you want your module to be imported:
http://python-notes.curiousefficiency.org/en/latest/python_concepts/import_traps.html#the-double-import-trap
https://pytest.org/latest/goodpractises.html
To find your unittests folder, since the name is not the conventional one (unit test scripts by default look for a test folder), you can use the discover option of the unittest module to tell how to find your test scripts:
python -m unittest discover unittests
Note that the first unittest is the Python module, and the second unittests (with an s) is your directory where you have placed your testing scripts.
Another alternative is to use the nosetest module (or other new unit testing modules like pytest or tox) which should automatically find your testing script, wherever you place them:
nosetests -vv
And to fix your import error, you should use the full relative (or absolute) path:
from ..MyClass import MyClass # Relative path from the unittests folder
from MyClass import MyClass # Absolute path from the root folder, which will only work for some unit test modules or if you configure your unit test module to run the tests from the root
A suggested structure, would be to look at your structure like this:
my_app
my_pkg
__init__.py
module_foo.py
test
__init__.py
test_module_foo.py
main.py
Run everything from within my_app, this way you will use all the same module references between your test code and core code.
Related
I'm trying to use nosetests to run my tests in a directory structure like this
src
- file1.py
- ...
test
- helper.py
- test_file1.py
As you can see, test_file1.py has some functions that test file1.py, so it imports file1.py like this:
# In file1.py
import file1
import helper
# Tests go here...
I also use a helper.py file that has some neat functionality built in so that I can create tests more easily. This functionality is achieved by extending a couple of classes in my actual code and overriding some methods. So helper.py looks something like this:
# In helper.py
import file1
# Use stuff in file1.py
I'm having trouble understanding how nose goes about importing these things with its custom importer. I was able to get my test file to import file1.py by running nosetest ../tests within the src directory, but I'm currently getting an error akin to:
File helper.py:
ImportError: cannot import name file1
How does nose do its imports and is there a way I can essentially get it to lump all my tests/src files together so they can all import one another while I keep them in separate folders?
Seeing that you execute tests with nosetests ../tests I assume they are executed from the tests folder itself. Therefore, files from the src directory are not added to sys.path, hence the error.
To fix this one could:
run tests from the parent directory - nosetests will be able to identify src and test (or tests) directory by himself and will add them to the sys.path before running tests
add src directory path to the PYTHONPATH before running nosetests (export PYTHONPATH=../src; nosetests)
Note that you can as well omit the last argument to the nosetests as by default it runs the tests from current directory. Otherwise, if the tests are not in the directory you launch nosetests from, you can define its location with --where=<path-to-tests> parameter (or, simply -w). So for example you can execute tests from src direcotory and without even setting the PYTHONPATH (because current directory will be added to sys.path by default) like this: nosetests -w ../tests.
Lastly, even though this is very questionable by itself, and yet: the most common way to organize a Python source code is having python files and packages starting directly in the project directory, and having tests in "test" sub-packages of the packages they test. So, in your case it would be:
/file1.py
/test/helper.py
/test/test_file1.py
or better:
/myproject/__init__.py
/myproject/file1.py
/myproject/test/__init__.py
/myproject/test/helper.py
/myproject/test/test_file1.py
(latter, provided you also use correct imports in your test sources, e.g. from .. import file1).
In which case one runs tests from the project's root directory simply with nosetests without any argument.
Anyway, nosetests is flexible enough to work with any structure - use whatever seems more suitable for you and the project.
More on project structure in What is the best project structure for a Python application?
This seems generally like an issue I had with nose tests:
Importing with Python and Nose Tests
The work around I found was to insert a try..except block so that BOTH python and nosetest commands will work on the same directory as follows:
(1) In your main file, at the very top before anything else add:
# In file1.py
try:
# This will allow you to do python file1.py inside the src directory
from file2 import *
from helper import *
except:
# This will allow you to run nosetests in the directory just above
# the src and test directories.
from src.file1 import *
from src.helper import *
(2) Inside your test.py file add:
from src.file2 import *
from src.helper import *
I have a project directory that is set up in the following way:
>root
> modules
__init__.py
module1.py
> moduleClass
__init__.py
moduleClass1.py
moduleClass2.py
> scripts
runTests.py
> tests
__init__.py
test1.py
test2.py
run.sh
In runTests.py I have the following import statements:
import modules.module1
import modules.moduleClass.moduleClass2
import tests.test1
import tests.test2
The first two import statements work fine, but the second two give me the errors ImportError: No module named test1 and ImportError: No module named test2. I can't see what is different between the tests and modules directories.
I'd be happy to provide more information as needed.
When you run a script, Python adds the script's containing directory (here, scripts/) to sys.path. If your modules don't appear in sys.path any other way, that means Python may not be able to find them at all.
The usual solution is to put your scripts somewhere in your module hierarchy and "run" them with python -m path.to.module. But in this case, you could just use an existing test runner: Python comes with python -m unittest discover, or you might appreciate something fancier like py.test (pip install --user pytest).
The problem turned out to be that python didn't like the folder name tests. Changing the name to unit_tests solved the problem.
I want to write my library in TDD methodology, but I have no idea how to design directory structure (or how to use unittest). Now I create a directory tree such as:
myproject (directory)
- tests (directory)
- src (directory)
- test.py (file running tests)
Each class from src has its own unittest class. Each directory has its own __init__.py file. I want to run tests only from test.py file and thanks to this each test can from src.modulename import classname and than runs test unittest.main() function. Unfortunately it doesn't work (runs zero tests).
Is this good approach? What are my mistakes?
The code in file test.py should look like:
from tests import *
import unittest
if __name__ == '__main__':
testsuite = unittest.TestLoader().discover('.')
unittest.TextTestRunner(verbosity=1).run(testsuite)
This code copies all tests from tests directory, because it copies entire package. The main method runs all test methods included in tests package's classes. Each test file name must start with test.
Here is my set up -
project/
__init__.py
prog.py
test/
__init__.py
test_prog.py
I would like to be able to run my unit tests by calling a command-line option in prog.py. This way, when I deploy my project, I can deploy the ability to run the unit tests at any time.
python prog.py --unittest
What do I need in prog.py, or the rest of my project for this to work?
The Python unittest module contains its own test discovery function, which you can run from the command line:
$ python -m unittest discover
To run this command from within your module, you can use the subprocess module:
#!/usr/bin/env python
import sys
import subprocess
# ...
# the rest of your module's code
# ...
if __name__ == '__main__':
if '--unittest' in sys.argv:
subprocess.call([sys.executable, '-m', 'unittest', 'discover'])
If your module has other command-line options you probably want to look into argparse for more advanced options.
Perhaps this is what you're looking for. Implement a load_tests function in test_prog.py and use the following code in prog.py to load and run the tests:
import unittest
import test.test_prog
suite = unittest.TestLoader().loadTestsFromModule(test.test_prog)
unittest.TextTestRunner().run(suite)
You must make sure that you consistently follow some naming conventions (which you seem to be doing):
All tests are named with the same prefix (test_ is the norm), followed by the name of the module you wish to test.
prog.py => test_prog.py
Tests reside in test/ directory.
Then you can do something like this:
prog.py
import sys
...
... do module stuff here...
...
if __name__ == "__main__":
# Check if we want to run the tests for this file
if "--unittest" in sys.argv:
import unittest
test_filename = 'test_' + __file__
test_directory = 'test'
suite = unittest.TestLoader().discover(test_directory, pattern=test_filename)
unittest.TextTestRunner(verbosity=2).run(suite)
What we are doing, is:
Checking the command arguments to see if --unittest is present (since that's the only time you want to run the tests).
If it is, then we create the test_prog.py - following the naming conventions we have set.
Then we pass that to the TestLoader().discover function.
discover(...) starts at the specified directory and finds all test modules (recursing into subdirectories ) that match the pattern provided.
In our case, it will look inside the test/ directory for any module named test_prog.py. When it does, it loads it and creates a TestSuite with the TestCases that we want to run.
Lastly, we manually test unittest to run the suite obtained in the previous step.
Normally, unittest will do all of this for us in the background, but since we are trying to run a specific test module, we have to tell exactly how and where to get it from.
Also, note that you will have to do this for every file where you want to do this at.
I just removed the .idea hidden directory under the project in the file system.
I restarted PyCharm, reopened the project, and this issue was resolved.
I have my code organized like this:
base_project_dir/src
/tests
/test1.py
/test2.py
in test1.py and test2.py I have the classes extending unittest.TestCase
according to python API doc, I should be able to run
python -m unittest tests from base dir and run all tests.
but doing so shows that it finds 0 tests. so I added
from test1 import *
from test2 import *
into tests/__init__.py
now the above command works. but when I want to run individual tests, it sources the module init, which forcefully run all tests.
what is the correct way to organize this?
thanks
Yang
Try this in your main project dir:
python -m unittest discover -v
This way you don't change the location for your relative imports. When you do python -m unittest tests it switches to this directory first and then can't import the projects code anymore.