I'm setting up a directory structure for my Django app to separate functional and unit tests. I am using nose as the test runner for my Django project.
At the root of the Django project, I have a folder called "tests" that has this structure:
tests
├── __init__.py
├── functional
│ ├── __init__.py
└── unit
├── __init__.py
├── data.py
├── tests.py
If I want to run just the unit tests, should I not be able to use the following from the project root:
$ nosetests tests.unit
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
As you can see, this doesn't find the tests in the tests.py file.
However, when I run using the directory structure, the tests are found as they should be:
$ nosetests tests/unit/
E
# .. Some errors I expected because settings are not initialized when called this way
-----------------
Ran 1 test in 0.001s
FAILED (errors=1)
What am I missing? My main issue is that I have a setup function in tests.unit.__init__.py that should be called for creating the data in the test DB for the upcoming tests.
Thanks
This all depends on what kind of code is in tests/unit/__init__.py
When you say
nosetests tests.unit
You are pointing to unit/__init__.py not the directory unit/ thus if you had no tests in your __init__.py module then nothing would be run. So it is understandable when you say you used the directory path and then your tests started working.
You mention
What am I missing? My main issue is that I have a setup function in
tests.unit.init.py that should be called for creating the data in
the test DB for the upcoming tests.
It is likely that although you have a setup function in __init__.py you may have not ever imported your test functions into __init__.py
One quick fix to this would be to add this line in __init__.py
from tests.unit.tests import *
That said it is really not very wise to be putting any code in __init__.py at all and if you have code that returns some kind of configuration data I would recommend creating a new library module with functions that will return configuration data to your tests
Related
I have the following folder structure in my project:
my-project
src/
__init__.py
script.py
test/
__init__.py
test_script.py
Ideally I want to have a separate folder where all the unit tests go. My test_script.py looks something like this:
from src.script import my_object
class TestClass(unittest.TestCase):
def test_script_object(self):
# unit test here
pass
if __name__ == 'main':
unittest.main()
When I try to run the script (using python test_script.py) I get the following error:
Traceback (most recent call last):
File "test_script.py", line 4, in <module>
from src.script import my_object
ModuleNotFoundError: No module named 'src'
I was following the instructions from this other thread, and I even tried appending src to the sys path (which forces me to change how I do imports in the rest of the project). When I'm not trying to append to the sys path, both of my __init__.py files are empty.
I am using python 3.8.
Does anyone have any suggestions? I'm new to unit testing in python, so maybe there is a better structure or other conventions I'm not aware of. Thanks in advance for your help!
Generally, any instructions that have you modifying sys.path in order to run your tests are sending you in the wrong direction. Your testing tool should be able to discover both your tests and your application code without requiring that sort of hackery.
I generally use pytest for running my tests. I would structure your example like this:
my-project/
├── src
│ ├── conftest.py
│ └── myproject
│ ├── __init__.py
│ └── script.py
└── tests
├── __init__.py
└── test_script.py
Assuming that src/myproject/script.py looks like this:
def double(x: int):
return x*2
And tests/test_script.py look like this:
import myproject.script
def test_double():
res = myproject.script.double(2)
assert res == 4
I can run tests from the my-project directory by simply running pytest:
$ pytest
========================================== test session starts ==========================================
platform linux -- Python 3.11.1, pytest-7.2.0, pluggy-1.0.0
rootdir: /home/lars/tmp/python/my-project
collected 1 item
tests/test_script.py . [100%]
=========================================== 1 passed in 0.00s ===========================================
In this setup, the file src/conftest.py is what allows pytest to automatically discover the location of your application code. Alternatively, you could instead specify that in your pyproject.toml file like this:
[tool.pytest.ini_options]
pythonpath = [
"src"
]
pytest also works if you write unittest-style tests as you show in your question; the above behavior would be identical if tests/test_script.py looked like:
import unittest
import myproject.script
class TestScript(unittest.TestCase):
def test_double(self):
res = myproject.script.double(2)
self.assertEqual(res, 4)
if __name__ == '__main__':
unittest.main()
(But I prefer pytest's simpler syntax.)
Possibly useful reading:
Good integration practices
If you really want to use unittest you can use the same directory layout, but you will need to update sys.path for it to run correctly. The easiest way to do that is:
PYTHONPATH=$PWD/src python -m unittest
This will automatically discover all your tests and run them. You can run a single test like this:
PYTHONPATH=$PWD/src python -m tests.test_script
You can avoid needing to modify sys.path if you use a simpler directory layout:
my-project/
├── myproject
│ ├── __init__.py
│ └── script.py
└── tests
├── __init__.py
└── test_script.py
Both pytest and python -m unittest, when run from the my-project directory, will correctly discover and run your tests without requiring any path modifications.
Let me say I'm still new to unit testing and using pytest.
I'm building unit tests and running them with GitHub Actions and I understand why it failed. I need to run the test modules in a specific order.
For reference, I have a following repo structure (generalized for simplicity)
mypackage/
├── __init__.py
├── foo.py
└── bar.py
tests/
├── __init__.py
├── test_foo.py
└── test_bar.py
My question (written for generalization): Is there a way to run specific test modules (not functions) in a given order with pytest? By default pytest will run in alphabetical order, i.e., test_bar before test_foo. However, in my case, test_bar uses data from test_foo, so I would like the order to be flipped. I can find other work arounds, but from my search I only found explanations of using pytest-order or pytest-ordering for specific functional orders in a given module. I thought this would be a good question for end-to-end testing while still ensuring 100% code coverage.
Thanks.
We using py.test. We try to put different conftest.py files in different folders to split our fixtures:
tests/api/
├── conftest.py
├── folder1
│ └── conftest.py
├── folder2
│ └── conftest.py
But when run the tests this error occurs:
____ ERROR collecting api/folder1/conftest.py ____
import file mismatch:
imported module 'conftest' has this __file__ attribute:
/tests/api/folder2/conftest.py
which is not the same as the test file we want to collect:
/tests/api/folder1/conftest.py
HINT: remove __pycache__ / .pyc files and/or use a unique basename for your test file modules
Why is that? How fix it?
PS. Removing __pycache__.pyc did not help.
PPS. __init__.py files already exist in each folder.
I had the same issue. To solve this you need to create python packages instead of directories. Then pytest will look at the conftest.py in your package instead of root directory. Hope, this will help you.
tests/api/
├── conftest.py
├── package1 # not folder
│ └── conftest.py
├── package2 # not folder
│ └── conftest.py
Your use case sounds like this example in the pytest documentation. Because of that I think it's possible to use conftest.pys at different levels to override fixtures.
The errors you're seeing may be related to incorrect imports. Is your test code importing from conftest files directly? Are your conftest files importing from your tests? Are any of your imports relative instead of absolute? If any of these are true, that may be your issue. I recommend only using absolute imports, and avoid imports between conftest.pys and test files.
Rename one (or both) of the test files Pytest is complaining about. Pytest is telling you in the error message to do this (i.e. change the basename, meaning don't name all your test files conftest.py). For example, you can fix it by doing:
tests/api/
├── conftest.py
├── folder1
│ └── test_conf1.py
├── folder2
│ └── test_conf2.py
In your case, the module names conflict (you have three conftest.pys). This is a quirk of Pytest AFAIK. Pytest could get around this by managing full package/module paths: but it doesn't do this (probably for good reason, but I do not maintain/contribute to pytest so I can't shed light on the issue). Pytest is a fantastic framework (it's even telling you exactly why it can't run your tests): I'm sure they have a good reason for not supporting this behavior.
You claim that you want to:
separate tests and fixtures by different functionalities.
So do that. Separating the test fixtures/functionalities has nothing to do with what you name the files.
I commonly run into this error when splitting up unit/integration/acceptance tests. I split them up so I can run my (fast) unit tests without having to run my (potentially slow) integration/acceptance tests. I might have some module, call it Abc. And I have something like:
tests/
├── unit
│ └── test_abc.py
├── integration
│ └── test_abc.py
But then pytest barfs with the identical error you've shown, and so I just rename integration/test_abc.py to integration/test_abc_integration.py and move on with my day. Like this:
tests/
├── unit
│ └── test_abc.py
├── integration
│ └── test_abc_integration.py
Is it annoying? A little. How long does the fix take? 5 whole seconds.
P.S. You might have to remove __pycache__ directories or you .pyc files for the first run after you get the error you've posted about (if you don't you'll just get the same error again even if you rename).
P.S.S. You can stop the Cpython interpreter (and most others) from writing out __pycache__ and .pyc files by calling python -B -m pytest .... The -B option makes the interpreter not save the bytecode to your filesystem. This results in some performance penalty whenever you run your test suite, but the penalty is usually very small (milage may vary). I typically use this option because I don't like the clutter in my repositories and the performance loss is typically negligible.
Problem
As part of python unittest, some input json files are to be loaded which exists under 'data' directory which resides in the same directory of test py file.
'pkg_resources' is used for this purpose.
It works fine when the unittest are running with python. But it fails when running with twisted trial.
My project has mixed testcases with both python unittest testcases as well as twisted.trial.unittest testcases. so, there is a need to run both type of testcases with twisted trial in general.
The '_trial_temp' directory is added in path when running testcases with twisted trial. please, let me know there is any way to handle this?
Example directory structure:
myproject/
└── tests
├── data
│ └── input.json
├── trialTest.py
trialTest.py
import unittest
import inspect
import pkg_resources
class Test(unittest.TestCase):
def test_01_pathTest(self):
dataDirExists = pkg_resources.resource_exists(inspect.getmodule(self).__name__, 'data')
print 'data exists: %s' % (dataDirExists)
if __name__ == '__main__':
unittest.main()
Running test using python and its output:
cd myproject
python tests/trialTest.py
data exists: True
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Running test using python and its output:
cd myproject
/usr/local/bin/trial tests/trialTest.py
trialTest
Test
test_01_pathTest ... data exists: False
[OK]
-------------------------------------------------------------------------------
Ran 1 tests in 0.013s
PASSED (successes=1)
In the first example, __name__ will be set to __main__, and the tests directory will be automatically added to sys.path. This works more or less by accident; if you move your unittest.main invocation to another module, you won't be able to import it quite the same way, and data may not show up.
In the second example, trial will, depending on the presence of an __init__.py file in the tests directory, set __name__ to either trialTest or tests.trialTest; or perhaps even myproject.tests.trialTest.
You should re-name the module to test_trialtest.py so that it is discovered by trial's module-walking code properly, and then invoke it with a module name rather than a file name. This means you should have a clear idea of what myproject/tests/test_trialtest.py's module name is supposed to be. Is myproject supposed to be on sys.path? The parent directory?
Basically, pkg_resources depends intimately on the details of the namespaces into which code is loaded and executed, so you need to be careful that everything is set up consistently. If you make sure that everything is imported the same way, under the same name (never as __main__, for example) then this should be totally consistent between trial and stdlib unittest; there's nothing really special about trial here except that you are running it (trial itself)` as the main script rather than your test script as the main script.
place an __init__.py in tests directory resolves the issue.
[durai#localhost myproject]$ touch tests/__init__.py
[durai#localhost myproject]$ tree
.
├── tests
├── data
│ └── input.json
├── __init__.py
├── trialTest.py
└── trialTest.pyc
[durai#localhost myproject]$ trial tests/trialTest.py
tests.trialTest
Test
test_01_pathTest ... currModule: <module 'tests.trialTest' from '/home/durai/Worskspace/myproject/tests/trialTest.pyc'>
currModule: tests.trialTest
data exists: True
[OK]
------------------------------------------------------------------------------ -
Ran 1 tests in 0.016s
PASSED (successes=1)
I have a module that sits in a namespace. Should tests and data the tests rely on go in the namespace or in the top level where setup.py sites?
./company/__init__.py
./company/namespace/__init__.py
./company/namespace/useful.py
./company/namespace/test_useful.py
./company/namespace/test_data/useful_data.xml
./setup.py
or
./company/__init__.py
./company/namespace/__init__.py
./company/namespace/useful.py
./test_useful.py
./test_data/useful_data.xml
./setup.py
Does the question amount to whether tests should be installed or not?
The Sample Project stores the tests outside the module.
The directory structure looks like this:
├── data
│ └── data_file
├── MANIFEST.in
├── README.rst
├── sample
│ ├── __init__.py
│ └── package_data.dat
├── setup.cfg
├── setup.py
└── tests
├── __init__.py
└── test_simple.py
Related: The Packing Guide: https://packaging.python.org/en/latest/
Hint: Don't follow the "The Hitchhiker's Guide to Packaging". It has not been updated since 2010!
(do not confuse both pages. The "The Hitchhiker’s Guide to Python" is a very solid book)
You should put your test module inside the module it tests according to The Hitchhiker's Guide to Packaging.
Here is their example:
TowelStuff/
bin/
CHANGES.txt
docs/
LICENSE.txt
MANIFEST.in
README.txt
setup.py
towelstuff/
__init__.py
location.py
utils.py
test/
__init__.py
test_location.py
test_utils.py
This way your module will be distributed with its tests and users can use them to verify that it works with their set up.
See http://the-hitchhikers-guide-to-packaging.readthedocs.org/en/latest/creation.html.
I personally create a single tests package as a sub package of the main package for a few reasons:
If tests is in parallel with the root package there's an off chance you, or a user may misconfigure setup.py and accidentally expose a global package named tests that will cause a great deal of confusion and headache until you realize what has happened. Putting it in the main module solves this as it's now under a (hopefully) globally unique namespace.
I don't like putting a test module within user package because test runners have to search through production code. This is probably not a problem for most. But, if you happen to be a hardware test engineer, you probably use the word 'test' a lot in your production code and don't want the unit test runner to pick that stuff up. It's much easier if all the tests are in one place separate from the production code.
I can further subdivide my tests folder into the types of tests, such as unit, functional and integration. My functional tests tend to have dependencies on weird proprietary hardware, data or are slow. So it's easy for me to continuously run just the fast unit test folder as I develop.
It can sometimes be convenient to have the tests be inside of the same package hierarchy as what it is testing.
Overall though, I think it's important to think for yourself about what's best for your particular problem domain after taking everyone's advice into account. 'Best practices' are great starting points, not end points, for developing a process.