django nose test, How to initialize a setup before any tests - django

I'm using django_nose for test django apps,
simply run python manage.py test
But, I wanna do a setup before any tests.
For example, create a file before test start. and then all the tests will using this file.
How to do this?
please help

As mentioned in nose docs, Test modules offer module-level setup and teardown; define the method setup, setup_module, setUp or setUpModule for setup. for e.g. setup_module() function: runs before anything else in the file

Related

Testing Django Apps On Heroku With Cypress

I'm a hobby web developer looking to build my first product with the django web framework which I will host on Heroku. Cypress looks like a great modern tool for UI testing which I certainly want to use. In local development I am using it within django testing so that the django staticliveservertestcase runs first - which creates a separate development server process, and a test database, if one hasn't been created already. Within this test I then call a bash script which executes a cypress UI test. See the example below.
Bash Script -
#!/bin/bash
echo $1 # the 1st command line argument
echo $2 # the 2nd command line argument
./node_modules/.bin/cypress run --env baseUrl=$1 --spec $2
Django Test Code -
class ExampleTest(StaticLiveServerTestCase):
def test_view_url(self):
from subprocess import run
exit_code = run([
'./cypress/run.sh',
f'http://{self.server_thread.host}:{self.server_thread.port}',
'cypress/integration/sample_spec.js'
])
self.assertEqual(0, exit_code.returncode)
From my understanding this is the opposite to the standard cypress approach. Normally cypress runs outside of the app independently and simply runs through all the tests which interact with the app. Here the cypress tests are called by the django process. Unless I am mistaken there are obvious advantages to this approach. I can test the UI and whether objects where created in the database after the UI test has run.
Is it possible, and if this how, to do this within Heroku? So Heroku would simply call the test script -
python manage.py test
And I get UI testing and unit testing all done in one go. It would also be nice to see the tests running in interactive mode. Which may be a challenge because Heroku obviously runs everything in a linux container - I don't plan on using Docker incidentally because I think that limits a lot of the features Heroku offers.

Disable migrations when running unit tests in Django 1.8?

Since upgrading my Django project to Django 1.8 using the default Django test runner, I'm finding that my tests take between 10 and 15 seconds to start up because of the new default behavior of running migrations before tests. It now takes longer for my test suite to start up then it does to run the actual tests themselves. I only have seven models, none of which are that complex, and over 180 tests. I'm running my tests against a PostgreSQL 9.4.4. database on a 1.86 GHz Mac laptop with 4 GB of RAM. I found this question which said to create a settings_test.py file that contains a MIGRATION_MODULE setting and then specify that settings_test file when running your tests. Could someone explain further how to implement this solution? Is the settings_test file supposed to look like this if you have two apps?
MIGRATION_MODULES={'app1': 'app1.migrations_not_used_in_tests',
'app2': 'app2.migrations_not_used_in_tests'}
If that's true, how would you run your tests as described if you have multiple apps?
DJANGO_SETTINGS_MODULE='???.settings_test' python manage.py test
I tried creating the exact settings_test.py file that specified 'myapp' even though I don't have an app named 'myapp' and while my tests ran, the migrations also ran prior to the tests as I expected they would. I'm sorry if this seems like a dumb question but I'm relatively new to Django.
Thanks.

How to run Django tests on Heroku

I have a app that is deployed to Heroku, and I'd like to be able to run the test suite post-deployment on the target environment. I am using the Heroku Postgres add-on, which means that I have access to a single database only. I have no rights to create new databases, which in turn means that the standard Django test command fails, as it can't create the test_* database.
$ heroku run python manage.py test
Running `python manage.py test` attached to terminal... up, run.9362
Creating test database for alias 'default'...
Got an error creating the test database: permission denied to create database
Is there any way around this?
Turns out I was in the wrong. I was not testing what I thought was being tested... Since Heroku's Routing Mesh was sending requests to different servers, the LiveServerTestCase was starting a web server on one machine and Selenium was connecting to other machines altogether.
By updating the Heroku Procfile to:
web: python src/manage.py test --liveserver=0.0.0.0:$PORT
overriding the DATABASES setting to point to the test database, and customizing the test suite runner linked to below (the same idea still holds: override setup_databases so that it only drops/re-creates tables, not the entire database), I was able to run remote tests. But this is even more hacky/painful/inelegant. Still looking for something better! Sorry about the confusion.
(updated answer below)
Here are the steps that worked for me:
Create an additional, free Postgres database using the Heroku toolbelt
heroku addons:add heroku-postgresql:dev
Use the HerokuTestSuiteRunner class which you'll find here.
This custom test runner requires that you define a TEST_DATABASES setting which follows the typical DATABASES format. For instance:
TEST_DATABASES = {
'default': dj_database_url.config(env='TEST_DATABASE_URL')
}
Then, have the TEST_RUNNER setting be a Python path to wherever HerokuTestSuiteRunner can be found.
You should now be able to run Django tests on Heroku using the given database. This is very much a quick hack... Let me know how it could be improved / made less hackish. Enjoy!
(original answer below)
A few relevant solutions have been discussed here. As you can read in the Django docs, "[w]hen using the SQLite database engine, the tests will by default use an in-memory database".
Although this doesn't thoroughly test the database engine you're using on Heroku (I'm still on the lookout for a solution that does that), setting the database engine to SQLite will at least allow you to run your tests.
See the above-linked StackOverflow question for some pointers. There are at least two ways out: testing if 'test' in sys.argv before forcing SQLite as the database engine, or having a dedicated settings file used in testing, which you can then pass to django manage.py test using the --settings option.
Starting with version 1.8, Django now has an option called keepdb, which allows for the same database to be reused during tests.
The --keepdb option can be used to preserve the test database between test runs.
This has the advantage of skipping both the create and destroy actions which can greatly decrease the time to run tests, especially those in a large test suite.
If the test database does not exist, it will be created on the first run and then preserved for each subsequent run.
Any unapplied migrations will also be applied to the test database before running the test suite.
Since it also allows for the test database to exist prior to running tests, you can simply add a new Postgres Heroku instance to your dyno and configure the tests to use that particular database.
Bonus : you can also use the failfast option, which exits as soon as your first test crashes, so that you don't have to wait for all tests to complete.
However, if you are deploying things to Heroku and you are using Heroku Pipelines, an even better option is available : Heroku CI.

Django separate DB engine for unit tests

I am new to Django and following several tutorials. I created a separate app for functional testing. I also setup a postgres DB engine for my prod DBMS but for testing I'd like to use SQLite3 in memory. Could someone tell me how to override the prod DB with another settings.py file? Where would I put the override file, in my functional test app folder? How does Django know which settings to use for prod vs. testing? Any help appreciated, thanks!
As an option:
Create a file names settings_test.py that contains something like:
from settings import * # if your main settings file is settings.py
DATABASES['default']['ENGINE'] = 'django.db.backends.sqlite3'
# and whatever other settings like db name etc.
Then run tests with the settings:
./manage.py test --settings=settings_test
Complementing Dima's answer, you can take a look at:
https://docs.djangoproject.com/en/1.4/internals/contributing/writing-code/unit-tests/#using-another-settings-module

How to test single application (not project) in Django?

I would like to test my small application, that I keep in a separate package. Right now I created a "test_project" directory, created a test project there and I am using the project's manage.py to run tests. But I keep wondering - is there a better method? Is it possible to launch a single app's tests, perhaps with some default configuration (like, sqlite database)?
It is possible to run a single app's tests standalone, without creating a Django test project for that purpose. One way of doing so is by creating a runtests.py in your app's root dir which setups Django settings and runs ./manage.py test your_app programmatically. One example of runtests.py is Django's own: runtests.py (documentation).
Django's own runtests.py is a good reference but I find it convoluted for most cases. Below are a couple of alternative examples:
Django-Modeltranslation
My own minimalistic one
Writing this down because I don't see it on here yet
From the docs
If your django structure looks something like this as it should:
Project dir/
/myapp
/myotherapp
/myproject
Django allows you to execute test from only "myotherapp" by executing:
./manage.py test myotherapp/
This will execute all test under "myotherapp" whereas
./manage.py test
will execute all test in your projects directory.
If you use nose you can run a single app's tests.
python manage.py test app.tests:TestClassHere
as for testing a single app. I just follow the convention other big django projects do, and that is exactly what you are doing. Create a test_project directory.
https://github.com/mozilla/django-piston/tree/master/tests/test_project
I figure if it is good enough for some of the biggest django pluggable apps it's good enough for me.
Ofcourse you can test the Python parts with a standalone unittest if you don't need any django dependencies
A Django environment requires atleast a settings.py and manage.py file. You can setup those with essential stuff only and UnitTest your app with manage.py. You should see a project as a Django runtime environment, there's no Django without it. You can probably mimic settings but tbh you would just be creating more hacks than simplicity.
You can also create a custom test runner and override the path it searches for tests in.
Perhaps I buried the lede here. I recently inherited a project that had legacy tests they wanted to keep for historical reasons, so I was forced to write all my tests in one folder and point to it
from django.test.runner import DiscoverRunner
class MyTestRunner(DiscoverRunner):
def __init__(self, *args, **kwargs):
kwargs.update({'top_level': str(settings.TEST_DISCOVER_TOP_LEVEL)})
super().__init__(*args, **kwargs)
def run_tests(self, test_labels, extra_tests=None, **kwargs):
# In order to override the top_level directory, the test_label must match the top_level
kwargs.update({'test_labels': [str(settings.TEST_DISCOVER_TOP_LEVEL)]})
return super().run_tests(extra_tests=extra_tests, **kwargs)
and in your settings
TEST_RUNNER = 'path.to.my.module.MyTestRunner'
TEST_DISCOVER_TOP_LEVEL = BASE_DIR / 'tests/unit_and_integration_tests'