I've created test.py module, filled with
from django.test import TestCase
from django.test.client import Client
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from forum.models import *
class SimpleTest(TestCase):
def setUp(self):
u = User.objects.create_user("ak", "ak#abc.org", "pwd")
Forum.objects.create(title="forum")
Site.objects.create(domain="test.org", name="test.org")
def content_test(self, url, values):
"""Get content of url and test that each of items in `values` list is present."""
r = self.c.get(url)
self.assertEquals(r.status_code, 200)
for v in values:
self.assertTrue(v in r.content)
def test(self):
self.c = Client()
self.c.login(username="ak", password="pwd")
self.content_test("/forum/", ['forum'])
....
and placed it in folder with my application.
When i run tests by
python manage.py test forum
after creating the test database i get an answer "Ran 0 tests in 0.000s"
What am i doing wrong ?
P.S.
Here is my project hierarchy:
MyProj:
forum (it's my app):
manage.py
models.py
views.py
tests.py
...
I renamed test.py to tests.py. Eclipse got that this module is with tests, but answer is still "Ran 0 tests in 0.000s"
You´ll need to use the prefix test_ for each test method.
Summary
Try running for your app only:
python manage.py test YOUR_APP
Check in your settings.py file if YOUR_APP is in INSTALLED_APPS config.
Test method should start with test_, e.g.:
def test_something(self):
self.assertEquals(1, 2)
If you are using a directory called tests instead of the tests.py file, check if it has a __init__.py file inside it.
If you are using a tests directory, remove tests.pyc and tests.pyo files. (__pycache__ dir for Python3)
Try renaming your method test to something like test_content.
I believe the test runner will run all methods named test_* (see the python docs for organising test code. Django's TestCase is a subclass of unittest.TestCase, so the same rules should apply.
You have to name it tests.py .
After some time spent in searching I did not find anyone suggesting this, so I will share it as a late answer.
In my case I have my manage.py in the root directory eg
.
...
├── dir
│ ├── project_name
│ ├── manage.py
│ ├── media
│ ├── app1
│ ├── static
│ ├── staticfiles
│ ├── templates
│ └── app2
...
so I found that the test command has the option to provide project which tests' to run. In my case I had to do this
python project_name/manage.py test ./project_name/
This successfully ran my tests.
There is something not quite right if you are getting the same result after renaming the file to tests.py. How are you running the tests? Are you doing so from the command line or have you set up a custom run target using Eclipse? Please try it from the command line if you haven't already.
Also fire up Django shell (python manage.py shell) and import your tests module.
from MyProj.forum.tests import SimpleTest
Does the import work correctly?
I had tried all these things but I neglected to add the __init__.py file in the tests directory that I created to hold all my tests and Django couldn't find it.
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.
I'm creating a pytest unit test for a function in my software.
Before even starting to test, pyunit seems to be unable to import my "cache_offline" decorator which is indirectly imported when I import the function I'm testing in my test.
I'm using Anaconda embedding Python 3.7 and pytest 5.2.2
I tried to comment out the code where the decorator is applied to my functions, when I do so the pytest error disappear and the tests execute properly.
My test is in ./tests/scripts/test_scripts_helper.py and I run pytest at the project root .
Pytest finds properly my test (see the error message), so this is not the problem at hand here.
My test imports and wants to test the function read_tiff_tag from a package vorace.scripts_helper, which imports a function safe_mkdir from package vorace.core.misc, which imports the package vorace.core.vorace, in which 3 functions are decorated with the decorator cache_offline from package vorace.core.misc
I tried both running the tests using either py.test or python -m pytest at the root of my project.
My project have the following structure (simplified).
The code root is ./vorace
The tests root is ./tests
.
├── conftest.py
├── tests
│ ├── __init__.py
│ ├── scripts
│ │ ├── __init__.py
│ │ └── test_scripts_helper.py
│ └── tests_data
│ └── test_ROI.tif
└── vorace
├── __init__.py
├── core
│ ├── __init__.py
│ ├── misc.py
│ └── vorace.py
└── scripts
├── __init__.py
├── batch_analyzis.py
└── scripts_helper.py
I tried :
with and without empty __init__.py in each subfolder of the tests folder. -> no change
with and without an empty conftest.py at the root of the project. -> no change
executing a test which doesn't need any import in my test_scripts_helper.py file (with my test causing the problem being commented out) -> the test executes properly
I suspect kind of a circular import problem but I've always been told that it can't happen in python. Maybe the decorators are an exception to this rule ?
My vorace.core.misc code, with the decorator
from vorace.core import vorace
[...]
def cache_offline(cache_path=os.getcwd()):
[...]
def decorator(func):
[...]
def wrapper(*args, **kwargs):
[...]
return result
return wrapper
return decorator
def safe_mkdir(path):
[...]
One of the decorated functions in vorace.core.vorace
from vorace.core.misc import *
[...]
#cache_offline(cache_path=".cache")
def classify_clusters_by_connectivity(xyz_data):
[...]
[...]
The output from executing py.test in the project root
==================== test session starts ====================
platform linux -- Python 3.7.3, pytest-5.2.2, py-1.8.0, pluggy-0.12.0
rootdir: /home/flo/PycharmProjects/VorAce
plugins: arraydiff-0.3, openfiles-0.3.2, doctestplus-0.3.0, remotedata-0.3.1
collected 0 items / 1 errors
==================== ERRORS ====================
_________ ERROR collecting tests/scripts/test_scripts_helper.py _________
tests/scripts/test_scripts_helper.py:1: in <module>
import vorace.scripts.scripts_helper as sh
vorace/scripts/scripts_helper.py:6: in <module>
from vorace.core.misc import safe_mkdir
vorace/core/misc.py:8: in <module>
from vorace.core import vorace
vorace/core/vorace.py:91: in <module>
#cache_offline(cache_path=".cache")
E NameError: name 'cache_offline' is not defined
If I execute a simple 0 == 0 test in my tests/scripts/test_scripts_helper.py file without importing from my project, the test runs with success.
When you run ./tests/scripts/test_scripts_helper.py python automatically sets ./tests/scripts/ into PYTHONPATH but not sets any other directories, so all your imports from other custom files should fail.
Set all your working directories into PYTHONPATH environment variable.
Something like that on Linux shell.
PYTHONPATH="${PYTHONPATH}:$dir
EDIT: I finally got the confirmation of a circular import.
At the opposite of what I thought, importing particular names from a module
like in from x import y can be sensitive to circular imports, where import x can't.
To solve it, I just imported the module and use the syntax using the module prefixing the function call.
More information here : https://www.reddit.com/r/Python/comments/51hdup/from_import_vs_import_on_circular_import/
The problem what finally not related specifically to the decorator or pytest.
I worked around this issue by putting my cache_offline decorator in a separated package vorace.core.caching.py. Now I import this package only from vorace.core.vorace where the function needing to be decorated resides.
This way my decorator is artificially excluded from the code imported by my unit test, but still available to the rest of my code for a normal application execution.
However pytest still have an issue here, it should not fail to import. I'm still taking any answer that can explain why pytest fails to import my decorator, and I keep the resolve for an answer of this kind.
my flask app is a package named app located at /Users/gexinjie/Codes/MyProject/xinnjie_blog
the file tree is like this
xinnjie_blog
├── app
| ├── __init__.py
│ ├── config.py
│ ├── exceptions.py
│ ├── model.py
│ ├── model_sqlalchemy.py
│ ├── static
│ ├── templates
│ ├── util.py
│ └── views
├── manage.py
I export it as PATHONPATH, so manage.py can import app
echo $PATHONPATH
/Users/gexinjie/Codes/MyProject/xinnjie_blog
and export FLASK_APP
echo $FLASK_APP
manage.py
current dir is /Users/gexinjie/Codes/MyProject/xinnjie_blog
pwd
/Users/gexinjie/Codes/MyProject/xinnjie_blog
here is the manage.py
import click
from app import create_app
app = create_app('development')
#app.cli.command()
def initdb():
click.echo('Init the db...')
here is app.__init__.py
from flask import Flask
from .model_sqlalchemy import db
def create_app(config_name='default'):
app = Flask(__name__)
... # init
return app
but then if I execute flask initdb, I get this error:
Usage: flask [OPTIONS] COMMAND [ARGS]...
Error: No such command "initdb".
and if I execute flask run, I get
Usage: flask run [OPTIONS]
Error: The file/path provided (manage) does not appear to exist. Please verify the path is correct. If app is not on PYTHONPATH, ensure the extension is .py
why manage.py is not found? And how can I fix it.
(actually it worked well when manage.py have flask app in itself )
# manage.py
# this work well
app = Flask(__name__) # not app = create_app('development')
Thank you
Thank to #Adam, This problem was solved after I uninstall Anaconda.
Because all the time I tested manage.py on Pycharm command tool, and that flask was installed by Anaconda(python version 3.6), it may lack some extensions(usually I use python3.5 on terminal).So I think the problem occur during importing.
The flask command tool complain about 'can't locate the app', but the real problem is import error.So that is so confusing.
"universal" solution:
So when if you come to this kind of problem like I do, I suggest you first check the location of your app(try both relative path and absolute path), relative path may cause the locate problem when you are not at the right working directory.So absolute path is recommend.
If every thing about path went well, then make sure that all the packages required by your app is installed and can be imported. if you are using some type of virtual environment or something like that (In my case, I use the other version of python lacking some flask extensions), it may be the import error makes flask complain.
Hope this can help you.
I have a package with a directory "tests" in which I'm storing my unit tests. My package looks like:
.
├── LICENSE
├── models
│ └── __init__.py
├── README.md
├── requirements.txt
├── tc.py
├── tests
│ ├── db
│ │ └── test_employee.py
│ └── test_tc.py
└── todo.txt
From my package directory, I want to be able to find both tests/test_tc.py and tests/db/test_employee.py. I'd prefer not to have to install a third-party library (nose or etc) or have to manually build a TestSuite to run this in.
Surely there's a way to tell unittest discover not to stop looking once it's found a test? python -m unittest discover -s tests will find tests/test_tc.py and python -m unittest discover -s tests/db will find tests/db/test_employee.py. Isn't there a way to find both?
In doing a bit of digging, it seems that as long as deeper modules remain importable, they'll be discovered via python -m unittest discover. The solution, then, was simply to add a __init__.py file to each directory to make them packages.
.
├── LICENSE
├── models
│ └── __init__.py
├── README.md
├── requirements.txt
├── tc.py
├── tests
│ ├── db
│ │ ├── __init__.py # NEW
│ │ └── test_employee.py
│ ├── __init__.py # NEW
│ └── test_tc.py
└── todo.txt
So long as each directory has an __init__.py, python -m unittest discover can import the relevant test_* module.
If you're okay with adding a __init__.py file inside tests, you can put a load_tests function there that will handle discovery for you.
If a test package name (directory with __init__.py) matches the
pattern then the package will be checked for a 'load_tests' function. If
this exists then it will be called with loader, tests, pattern.
If load_tests exists then discovery does not recurse into the package,
load_tests is responsible for loading all tests in the package.
I'm far from confident that this is the best way, but one way to write that function would be:
import os
import pkgutil
import inspect
import unittest
# Add *all* subdirectories to this module's path
__path__ = [x[0] for x in os.walk(os.path.dirname(__file__))]
def load_tests(loader, suite, pattern):
for imp, modname, _ in pkgutil.walk_packages(__path__):
mod = imp.find_module(modname).load_module(modname)
for memname, memobj in inspect.getmembers(mod):
if inspect.isclass(memobj):
if issubclass(memobj, unittest.TestCase):
print("Found TestCase: {}".format(memobj))
for test in loader.loadTestsFromTestCase(memobj):
print(" Found Test: {}".format(test))
suite.addTest(test)
print("=" * 70)
return suite
Pretty ugly, I agree.
First you add all subdirectories to the test packages's path (Docs).
Then, you use pkgutil to walk the path, looking for packages or modules.
When it finds one, it then checks the module members to see whether they're classes, and if they're classes, whether they're subclasses of unittest.TestCase. If they are, the tests inside the classes are loaded into the test suite.
So now, from inside your project root, you can type
python -m unittest discover -p tests
Using the -p pattern switch. If all goes well, you'll see what I saw, which is something like:
Found TestCase: <class 'test_tc.TestCase'>
Found Test: testBar (test_tc.TestCase)
Found Test: testFoo (test_tc.TestCase)
Found TestCase: <class 'test_employee.TestCase'>
Found Test: testBar (test_employee.TestCase)
Found Test: testFoo (test_employee.TestCase)
======================================================================
....
----------------------------------------------------------------------
Ran 4 tests in 0.001s
OK
Which is what was expected, each of my two example files contained two tests, testFoo and testBar each.
Edit: After some more digging, it looks like you could specify this function as:
def load_tests(loader, suite, pattern):
for imp, modname, _ in pkgutil.walk_packages(__path__):
mod = imp.find_module(modname).load_module(modname)
for test in loader.loadTestsFromModule(mod):
print("Found Tests: {}".format(test._tests))
suite.addTests(test)
This uses the loader.loadTestsFromModule() method instead of the loader.loadTestsFromTestCase() method I used above. It still modifies the tests package path and walks it looking for modules, which I think is the key here.
The output looks a bit different now, since we're adding a found testsuite at a time to our main testsuite suite:
python -m unittest discover -p tests
Found Tests: [<test_tc.TestCase testMethod=testBar>, <test_tc.TestCase testMethod=testFoo>]
Found Tests: [<test_employee.TestCase testMethod=testBar>, <test_employee.TestCase testMethod=testFoo>]
======================================================================
....
----------------------------------------------------------------------
Ran 4 tests in 0.000s
OK
But we still get the 4 tests we expected, in both classes, in both subdirectories.
The point using init.py, is that one may encounters side effects, like file not being the script file path. Using FOR DOS command can help (not found of DOS commands, but sometimes it helps
setlocal
set CWD=%CD%
FOR /R %%T in (*_test.py) do (
CD %%~pT
python %%T
)
CD %CWD%
endlocal
/R allows for walkthrough the hierarchy from current folder.
(expr) allows for selecting test files (I use _test.py)
%%~pT is $(dirname $T) in shell.
I saved and restore my original directory, as the .bat leaves me where it ends
setlocal ... endlocal to not pollute my environment with CWD.
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)