Nose: test all modules in a given package - python

I have a package with several sub-packages, one of them for tests (named tests). Since the sub-package name makes it clear that contained modules are test modules, I prefer not to pollute module names with the test-name pattern nose expects to include them for testing. That's the setup I'm thinking of:
- foo
- __init__.py
...
- bar
- __init__.py
...
- baz
- __init__.py
...
- tests
- __init__.py
- something.py
Now, by default nose does not run tests found in foo.tests.something. I know nose accepts the -i option to define regular expressions for additional stuff to search tests in. So nose -i something does the job here. However, I have a bunch of modules in the tests package and do not want to name them explicitely. nose -i tests\..* does not work, it looks like nose only matches against module base-names. As a last resort I could run nose --all-modules, but this also inspects foo.bar and foo.baz -- I'd like to avoid this.
So, how could I instruct nose to look for tests in all modules within a given package (tests in my case)? I could write a nose plugin for this task, but I'm looking for a standard solution.

If you name the files in tests with a test_ prefix (i.e. rename something.py to test_something.py, running nose should pick them up by default.
You say "I prefer not to pollute module names with the test-name pattern nose expects to include them for testing", but "something" isn't descriptive of the file, because the file tests that something. What's the problem with using the non-confusing, standard way of naming your tests?

You should be able to import the files into your __init__.py and have them picked up. I had this setup:
- app:
- __init__.py
- models.py
- views.py
- tests:
- __init__.py
- models.py # contain tests
- views.py # contain tests
In the tests/__init__.py file I had the following:
from app.tests.models import *
from app.tests.views import *
Which defeats one of the benefits of using a regex to find tests (a goal of nose) but worked.
You can also use the decorator #istest to flag an individual def as a test if you want to avoid the naming of methods to match the regex. I've not tried to do this for modules (py files) that don't also match the regex but I doubt it would work without the above import.
Note, I've moved away from the import in __init__.py and just prefix my test methods and filenames with test_ and postfix my classes with Test. I find this makes the code more self-describing as even in a Test class there may be setup methods and helper methods (e.g. generators).

with Nose:
nosetests --all-modules
With py.test it can be done by put this in setup.cfg (configure file):
[pytest]
python_files=*.py
check this doc: pytest docs.

Related

File naming conventions for unittesting files

For python unit tests, is the following a common naming convention?
MyProject/
run_ingest.py
tests/
run_ingest.py
Or is this too redundant? If so, what would be a better naming convention or directory structure to put testing code?
Having a directory called tests is correct but, as per my experience, the test scripts themselves are usually prefixed with test_ so in your case test_run_ingest.py. Make sure to use underscore rather than - as a separator in the names to avoid import problems. As for the structure, you'd also probably want to include __init__.py files both to the top level and /tests folder to simplify imports.
If you are new to unittest this blog might be of interest.
Add a little bit to Alexander's answer. In test_run_ingest.py, write from run_ingest import *, and when testing, cd to MyProject and type python3 -m unittest tests.test_run_ingest

Release application tests as a Python module

I'd like to have my tests on a module of its own that could be imported, but keeping them outside the src folder and at the same time sharing the namespace with the application module (something like my-module.test.unit) Is it even possible? Am I complicating it too much?
Directory structure:
root/
src/
my-module/
test/
end-to-end/
unit/
helper.py
test_foo.py
setup.py
setup.py
setup(
# ...
'packages'=['my-module'],
'package_dir'={'': 'src'}
# ...
)
Possible options I've figured:
Python's Namespace Packages
Change setup.py:
setup(
# ...
'packages'=['my-module', 'my-module.test.unit'],
'package_dir'={
'my-module': 'src', # doesn't work in editable mode
'my-module.test.unit': 'test/unit'
}
# ...
)
Create another setup.py inside the test folder
The rationale is that I have some helper modules in the same folder than the tests (e.g. test/unit/helper.py) and they are imported using absolute imports (e.g. from helper import Helper). There's nothing necessarily wrong in this setup because it works, but hypothetically a new built-in module could shadow any of mine because they take precedence. I believe that relative imports are better because there is no room left for interpretations (explicit is better than implicit). AFAIK, if my tests were a package by themselves I could bring that modules using relative imports (e.g. from .helper import Helper).
In the end it's more a matter of good practices and correctness than a real issue and because of that practicality beats purity also applies ;)
References on this:
Importing from builtin library when module with same name exists
PEP 0328 - Rationale for Relative Imports

Cannot run tests with nosetests

I am trying to use nosetests to run all test cases inside my project.
I cd to my project directory:
cd projects/myproject
Then I do:
nosetests
Which outputs:
----------------------------------------------------------------------
Ran 0 tests in 0.001s
OK
Inside projects/myproject I have a package called Encode and inside the package I have Test directory with tests:
Encode/
__init__.py
Video.py
Ffmpeg.py
Test/
VideoTest.py
FfmpegTest.py
Why is nosetests not detecting my unit tests? All of my unit test classes extend unittest.TestCase.
From the nose docs:
Any function or class that matches the configured testMatch regular expression ((?:^|[\b_\.-])[Tt]est) by default – that is, has test or Test at a word boundary or following a - or _) and lives in a module that also matches that expression will be run as a test.
Your tests aren't being found because your filenames don't match the pattern. Change them to Video_Test.py, or Test_Video.py, for example. BTW: It's also odd that they have camelCase names like that, but that won't stop them from working.
nose won't find your tests if they are buried in a subdirectory. You should be able to tell it where to look though. Try nosetests --where=Encode/Test.

Intrapackage module loads in python

I am just starting with python and have troubles understanding the searching path for intra-package module loads. I have a structure like this:
top/ Top-level package
__init__.py Initialize the top package
src/ Subpackage for source files
__init__.py
pkg1/ Source subpackage 1
__init__.py
mod1_1.py
mod1_2.py
...
pkg2/ Source subpackage 2
__init__.py
mod2_1.py
mod2_2.py
...
...
test/ Subpackage for unit testing
__init__.py
pkg1Test/ Tests for subpackage1
__init__.py
testSuite1_1.py
testSuite1_2.py
...
pkg2Test/ Tests for subpackage2
__init__.py
testSuite2_1.py
testSuite2_2.py
...
...
In testSuite1_1 I need to import module mod1_1.py (and so on). What import statement should I use?
Python's official tutorial (at docs.python.org, sec 6.4.2) says:
"If the imported module is not found in the current package (the package of which the current module is a submodule), the import statement looks for a top-level module with the given name."
I took this to mean that I could use (from within testSuite1_1.py):
from src.pkg1 import mod1_1
or
import src.pkg1.mod1_1
neither works. I read several answers to similar questions here, but could not find a solution.
Edit: I changed the module names to follow Python's naming conventions. But I still cannot get this simple example to work.
The module name doesn't include the .py extension. Also, in your example, the top-level module is actually named top. And finally, hyphens aren't legal for names in python, I'd suggest replacing them with underscores. Then try:
from top.src.pkg1 import mod1_1
Problem solved with the help of http://legacy.python.org/doc/essays/packages.html (referred to in a similar question). The key point (perhpas obvious to more experienced python developers) is this:
"In order for a Python program to use a package, the package must be findable by the import statement. In other words, the package must be a subdirectory of a directory that is on sys.path. [...] the easiest way to ensure that a package was on sys.path was to either install it in the standard library or to have users extend sys.path by setting their $PYTHONPATH shell environment variable"
Adding the path to "top" to PYTHONPATH solved the problem.To make the solution portable (this is a personal project, but I need to share it across several machines), I guess having a minimal initialization code in top/setup.py should work.

`python -m unittest discover` does not discover tests

Python's unittest discover does not find my tests!
I have been using nose to discover my unit tests and it is working fine. From the top level of my project, if I run nosetests I get:
Ran 31 tests in 0.390s
Now that Python 2.7 unittest has discovery, I have tried using
python -m unittest discover
but I get
Ran 0 tests in 0.000s
My directory structure is:
myproj/
reporter/
__init__.py
report.py
[other app modules]
tests/
__init__.py
test-report.py
[other test modules]
Do you have any ideas why unittest's discovery algorithm can't find the tests?
I'm using Python 2.7.1 and nose 1.0.0 on Windows 7.
The behaviour is intentional, but the documentation could make this clearer. If you look at the first paragraph in the test discovery section, it says:
For a project’s tests to be compatible with test discovery they must all be importable from the top level directory of the project (in other words, they must all be in Python packages).
A corollary to that is that the file names must also be valid Python module names. test-report.py fails that test, since test-report is not a legal Python identifier.
A docs bug suggesting that this be mentioned explicitly in the documentation for the -p pattern option would probably be a good way forward.
I had this problem because some directories in a project were missing __init__.py. I thought I don't need them in Python 3.7.
Just add __init__.py to every directory and python3 -m unittest will find tests automatically.
As someone relatively new to Python, the naming convention in the docs implied the opposite. Ben's comment was very helpful: the default discovery pattern looks for test-modules prefixed with the string "test"
I thought the introspection would just look for class names and not require a specific file naming convention.
Here is what the docs say:
https://docs.python.org/3/library/unittest.html
python -m unittest discover -s project_directory -p "_test.py"
I couldn't get this to work, but by changing my file names to be "test_.py" - success!

Categories