Django testing external script - python

I want to perform testing on a script that interacts with my Django application, namely the database. Normally, when we want to test something in Django we simply fire up the built in test suite. With this test suite we even get nice command line switches such as overriding the built in settings.py with a different settings file:
python manage.py test myApp --settings='settings_test'
Here is the problem:
1) I want to test said script which is not part of an app, so I know of no way to invoke the test suite using manage.py. Is this possible? I.e.:
python manage.py test /path/myScript.py --settings='settings_test'

I would suggest to use a different test runner.
You can do pip install django-nose and then set the following setting in your test_settings.py
TEST_RUNNER = `django_nose.NoseTestSuiteRunner`
Now you can run the tests with
./manage.py test --settings=yourproject.test_settings.py
and the Nose testrunner will search all subfolders for folders called tests and in those folders it will search for files that end with _tests.py (and in those files it will search for classes that derive from TestCase, as usual).
So your project structure should look something like this:
- Project-Root/
- Your-Non-App-Code/
- __init__.py
- non_app_code.py
- tests/
- __init__.py
- non_app_code_tests.py
For more info on how to install django-nose, check their Github repo: https://github.com/django-nose/django-nose

Related

CodeCov is ignoring certain files. No settings for ignore in YAML. Python/Django

I have a Python Django project on GitHub and I'm using CodeCov with this project.
I have two apps in this Django project, a general app, and a general_api app. For some reason, all of the changes made in the general_api app files are being ignored.
I had YAML settings like this to ignore my test cases:
codecov:
require_ci_to_pass: false
ignore:
- (?s:test_[^\/]+\.py.*)\Z
- (?s:tests_[^\/]+\.py.*)\Z
- ^test.py.*
- ^tests.py.*
However, I've removed them with the same issue.
Is there some other way to ignore, or set the ignore parameters in CodeCov other than the YAML settings?
The root of my problems was actually in how I was using coverage to generate my coverage report.
I was previously using the command line: coverage run -m pytest
This only creates a coverage report on files that have test cases against them or files that are interacted with while testing. Files that have no interaction or test cases would be completely omitted.
I found through the coverage documentation, that I needed to add --source=. to my command line if I wanted the coverage report to include untested files. This is now showing all files in my root source.
The final command was: coverage run --source=. -m pytest

How to disable Django's Test Discovery?

This is an unusual situation - most Django users want Django's test runner to find all of their tests.
I'm working on a python library with several test suites that are run with different configurations, so I don't want the discovery to find and run tests from the wrong configuration. How do I disable discovery entirely and rely on the pre-1.6 behavior of only running the tests for apps explicitly declared in INSTALLED_APPS?
My library structure:
library/ # django app used by others
tests/ # custom test suites here
core/ # tests of core functionality
custom/ # tests of a custom feature requiring separate config
contrib/ # tests for assorted contrib features, also requiring separate config
manage_core.py # separate manage.py files for each "project"
manage_custom.py # these specify settings file to use.
manage_contrib.py
settings.py # base settings for all tests
settings_core.py # settings for 'core' tests including unique INSTALLED_APPS
settings_custom.py # settings for 'custom' tests; different INSTALLED_APPS
settings_contrib.py # settings for 'contrib' tests; different INSTALLED_APPS
The problem is that this command, which should only run tests for the 'contrib' test suite, is also finding and running tests for 'core':
./manage_contrib.py test contrib.tests
It's missing from the Django docs, but the command-line has an option, found via ./manage.py help test:
-t TOP_LEVEL, --top-level-directory TOP_LEVEL
Top level of project for unittest discovery.
Confusingly, specifying the module to test doesn't appear to prevent test discovery, but specifying a sub-directory does, like this:
./manage_contrib.py test contrib.tests -t ./contrib/
That appears to prevent the discovery of tests located outside of contrib.
Hmm I'm unfortunately not aware of a settings parameter that might let you tell unittest to only run from individual apps (a-la "settings.TEST_DIRECTORIES=settings.INSTALLED_APPS") but if you're able to give your tests a unique naming convention, you could use the --pattern= option when running the test suite.
For example, if you have
/myapp/tests/test_a_models.py
/myapp/tests/test_b_models.py
You could only run a with ./manage.py test --pattern='*_a_*' and then run b with ./manage.py test --pattern='*_b_*'
Definitely not ideal, but might get the job done depending on how much flexibility you have with the test naming conventions in your own app.

How to setup web2py enviroment for unittest

I have the following directory structure:
web2py/applications/myapp
web2py/applications/myapp/controllers/account.py
web2py/applications/myapp/models/db.py
web2py/applications/myapp/tests/runner.py
web2py/applications/myapp/tests/test_account.py
In account.py, there is a function accessing models/db.py, for instance
def calcExpense():
rows = db(db.expense.id >0).select()
expense = blah and blah..
return expense
In test_account.py, I would like to test calcExpense:
class TestAccount(unittest.TestCase):
def testCalcExpense(self):
self.assertTrue()
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestAccount))
unittest.TextTestRunner(verbosity=2).run(suite)
If I run under web2py directory with python web2py.py -S myapp -M -R applications/myapp/tests/test_account.py, everything is fine thanks web2py setting all required environment.
But I don't want to run unittest one way for web2py (under web2py directory), and another way for the all other python projects (under tests).
In particular, I want to run all tests through the test runner, under tests by:
`python -m unittest -v runner`
How can I setup the enviroment in runner.py, so that test_account.py can import account.py, account.py have access to both db.py and tables defined in db.py?
You can create a web2py environment using the env function in the gluon.shell module. For some ideas on how to proceed, check out web2py.test, in particular, here.
You might also want to look at an older project, web2py Test Runner.

Django unit tests: Can I specify default label/location?

I know that when I run
$ ./manage.py test
then it will discover tests in any file named test*.py under the current working directory.
I also know that I can specify a test label like this:
$ ./manage.py test animals.tests
Then all the tests in the animals.tests module will be run.
Another option is to specify a directory like this:
$ ./manage.py test animals/
And then all the tests in the animals/ directory will be discovered and run.
(The examples above are from the docs.)
I'd like to know if there is a way to specify a default test label to be tested or a directory to be used for tests discovery.
Let's say I'd like to run the tests in animals/ directory by default (i.e. if not specified otherwise). Then the following two commands would be equal:
$ ./manage.py test
$ ./manage.py test animals/
Although I would still like to be able to run another tests like this:
$ ./manage.py test people/
Thank you.
P.S. I know that I could redefine the test management command but I'd rather avoid doing this. I'm looking for a cleaner solution - such as a configuration option etc.

Py.test No module named *

I have a folder structure like this
App
--App
--app.py
--Docs
--Tests
--test_app.py
In my test_app.py file, I have a line to import my app module. When I run py.test on the root folder, I get this error about no module named app. How should I configure this?
Working with Python 3 and getting the same error on a similar project layout, I solved it by adding an __init__ file to my tests module.
$ touch tests/__init__.py
I'm not great at packaging and importing, but I think that this helps pytest work out where the target App module is located.
I already had an __init__.py file in the /App/App directory and wanted to run tests from the project root without any path-mangling magic:
python -m pytest tests
The output immediately looks like this:
➟ python -m pytest tests
====================================== test session starts ======================================
platform linux -- Python 3.5.1, pytest-2.9.0, py-1.4.31, pluggy-0.3.1
rootdir: /home/andrew/code/app, inifile:
plugins: teamcity-messages-1.17
collected 46 items
... lines omitted ...
============================= 44 passed, 2 skipped in 1.61 seconds ==============================
I had a similar problem and had to delete __init__.py from the root and add an __init__.py to the tests folder.
So you are running py.test from /App. Are you sure /App/App is in your $PYTHONPATH?
If it's not, code that tries to import app will fail with such a message.
EDIT0: including the info from my comment below, for completeness.
An attempt to import app will only succeed if it was executed inside /App/App, which is not the case here. You probably want to make /App/App a package by putting __init__.py inside it, and change your import to qualify app as from App import app.
EDIT1: by request, adding further explanation from my second comment below.
By putting __init__.py inside /App/App, that directory becomes a package. Which means you can import from it, as long as it - the directory - is visible in the $PYTHONPATH. I.e. you can do from App import app if /App is in the $PYTHONPATH. Your current working directory gets automatically added to $PYTHONPATH, so when you run a script from /App, the import will work.
Running pytest with the python -m pytest command helps with this exact thing.
Since your current package is not yet in your $PYTHONPATH or sys.path - pytest gets this error.
By using python -m pytest you automatically add the working directory into sys.path for running pytest. Their documentation also mentions:
This is almost equivalent to invoking the command line script pytest
I also got same error while running test cases for my app located as below
myproject
--app1
--__init.py__
--test.py
--app2
--__init.py__
--test.py
--__init.py__
I deleted my myproject's init.py file to run my test cases.
TL;DR
You might as well add an empty conftest.py file to your root app folder.
(if you take a look at the question folder structure, that would be the same level as the "Tests" folder, not inside of it).
More info:
Pytest looks for conftest.py files inside all your project folders.
conftest.py provides configuration for the file tree pytest finds it in. Because pytest somehow scans all subdirectories starting from conftest.py folder, it should find packages/modules outside the tests folder (as long as a conftest.py file is in your app root folder).
Eventually, you might want to write some code in your empty conftest.py, specially to share fixtures among different tests files, in order to avoid duplicate code. Afterall, the DRY principle (Don't Repeat Yourself) should also be follwed when writing tests.
Adding __init.py__ to the tests folder also should help pytest to find modules throughout your application. However, note that Python 3.3+ has implicit namespace packages that allow it to create a packages without an __init__.py file. That been said, creating __init__.py files for this specific purpose seems more like a a workaround for pytest than a python requirement. More about that in: Is __init__.py not required for packages in Python 3.3+
I got the similar issue. And after trying multiple things including installing pytest on virtual environment and adding/removing __init__.py file from the package, none worked for me.
Solution that worked for me is(windows solution):
Added Project folder(not package folder) to python path(set PYTHONPATH=%PYTHONPATH%;%CD%)
Ran my script from Project Folder and boom, it worked.
I hit the same issue.
my-app
--conf
--my-app
--tests
I set the __init__.py files. I added a conftest.py ( for sharing pytest.fixtures ). I added this to my Poetry file ( pyproject.toml:
[tool.pytest.ini_options]
pythonpath = [
"."
Turned out it was my use of hyphens and not underscores ! Noo...
# pytest can't find Module
--my-app
# works
--my_app
What worked for me: I had to make absolute imports in my test file and call python -m test in the root folder.
This worked for me:
Went to parent app, and pip install -e . (install a local and editable app).

Categories