I used to have a standalone script with some unit tests to test data in our database. I did not use the builtin Django testing tool, as that would create an empty testing database, which is not what I want.
In that script, I created three different classes extending unittest.TestCase containing some test functions that directly executed SQL statements.
Now I would prefer to be able to access the Django ORM directly. The easiest way to do this is via a custom management commant (./manage.py datatests).
In the standalone script, I could call all unit tests via the following function:
if __name__ == '__main__':
unittest.main()
It would discover all tests in the current file and run them.
How can I do an equivalent thing (run some test suites) from within a custom Django management command?
I'm sorry for not having searched for an answer long enough before asking, but I found the solution to this problem myself in another Stackoverflow answer:
How to run django unit-tests on production database?
Essentially, instead of unittest.main() the following code can be used:
suite = unittest.TestLoader().loadTestsFromTestCase(TestCaseClass)
unittest.TextTestRunner(verbosity=2).run(suite)
This will load all tests in the specified TestCaseClass. If you want to load all tests in the current module, creating the suite this way will help:
suite = TestLoader().loadTestsFromName(__name__)
The Stackoverflow answer linked above contains a full example. Furthermore, the Basic Example section of the unittest module docs describes the same thing. For other options to load tests, see Loading and running tests in the docs.
You may want to specify the contents of your start-up db through fixtures. It will load up the context for db for particular test. And you can take a snapshot of db with
$ ./manage.py dumpdata my_app > fixtures/my_pre_test_db.json`
Now in your unit test you will have something like this:
class MyTestCase(TestCase):
fixtures = ['fixtures/my_pre_test_db.json']
def testThisFeature(self):
...
Related
pytest module scoped fixtures that use the django test database are perplexing us. We want a fixture, that creates an entry in the database, once per test module.
This works, but it's very clunky:
import pytest
#pytest.fixture(scope='module')
def site(django_db_setup, django_db_blocker):
with django_db_blocker.unblock():
address = models.Address.create(..)
site = models.Site.create(address=address, ..)
yield site
with django_db_blocker.unblock():
site.delete()
address.delete()
We've noticed that django_db_setup is required, because if this fixture is the first one called, the test database won't be set up and the fixture will be created in the non-test database!
For complicated objects that have more than one or two related models, the fixture becomes very ugly.
Is there a better way to do this?
I'm trying to create tests for my Django application but I'm having some trouble creating a test database.
I'd like to keep the existing structure while entering new curated test-information, creating test users, uploading test content, etc. Which I can then populate a test database with so that I have curated data on which I can test edge-cases.
Creating a test database seems simple, just run python manage.py test --keepdb. Getting entries into it seems more difficult.
Is it possible to run Django in "test mode" with the test database being used so that I can use the website UI to enter all the data, or is there some other better way to do it entirely?
I assume you mean testing with unit tests?
Usually you fill the database with fixtures, or some other test data that is populated into the database as a part of the test itself.
Django fixtures: https://code.djangoproject.com/wiki/Fixtures
Fixtureless is a good option, https://pypi.org/project/django-fixtureless/
Factory Boy http://factoryboy.readthedocs.io/en/latest/
These options allow you to fill your database with fake or static data to use in your tests.
How do I populate the test database created while testing the Django test cases with the values from some other database(for ex: the Production database.)
In detail:
when I run the below command,
$ python manage.py test
a test data base is created for the testing purpose, but it doesn't have any data in it. I want the test database created to be populated with some initial values.
Thanks..
You can use dumpdata to get a file with data from your live db.
Then you can load data from a file automatically for a test (see Django tests):
from django.test import TestCase
from django.core.management import call_command
class Tests(TestCase):
#classmethod
def setUpTestData(cls):
call_command('loaddata', 'myfile', verbosity=0)
You may use django fixtures to populate your test database.
Create a fixture of your production db and write it to some file
python manage.py dumpdata > backup.json
You can populate your test database using this command
python manage.py loaddata backup.json
if you want to do this by running python manage.py test then you should write custom django-admin commands
You want to check out fixtures. Here's a link to docs page: https://docs.djangoproject.com/en/1.8/howto/initial-data/
Basically you might want to dump your current database for testing purposes, so you'd do something like:
python manage.py dumpdata
Then you want to place your file in a directory that Django will look for fixtures. You can either specify it in settings with FIXTURE_DIRS variable or use default. The default is simply inside a fixtures directory in your Django app.
I have a few functional tests for an app I am developing. For every test, I need to create an admin user, and then also a few profiles of users of the app. Creating the admin and the user profiles does not take too long if you are running one test only, but it adds up when I run all tests, which is required every time we add a new feature to the add.
I have a Python file with the following:
import unittest, sys
from django.conf import settings
print("DEV_ENV: "+str(settings.DEV_ENV))
print("TEST_ENV: "+str(settings.TEST_ENV))
print("PROD_ENV: "+str(settings.PROD_ENV))
from case1test import Case1Test
from case2test import Case2Test
from case3test import Case3Test
from case4test import Case4Test
if __name__ == '__main__':
unittest.main()
I would like to create the admin and user profiles ONCE for all functional tests. Can someone give me some advice on how to proceed? The app is developed using Django 1.6, so the --keepdb option is not available.
They are many ways to do that :
With fixtures:
Add a fixture file in yourapp/fixtures/, I suggest you to dump a new one with ./manage.py dumpdata yourapp.yourmodel --pks=<instance_id>. Simply load needed fixture in your tests.
With little fixture loading is fast but if you deal with bigger sizes you can use Django-nose and hisFast Fixtures feature
With Factory Boy:
A library for building set of objects/models with (±) small declaration
I'm working on a web project in Django, and I'm using the python unittest framework. For every app I have some fixtures. This means, that every app has some identical tables in fixtures. I would like to share fixtures between apps and testcases, because otherwise if I change a model, I will have to change all json fixtures where this concrete table is referenced.
Is it sensible to use global fixtures?
Do not use static fixtures, it is a bad automated tests pattern. Use dynamic fixtures.
Django Dynamic Fixture has options to create global fixtures. Check its Nose plugin or the Shelve option.
I would highly recommend looking into Django's Testing architecture. Check out TestCase.fixtures especially; this is far more advanced and Django-specific than unittest.
I can't think of anything wrong with using global fixtures as long as you delete them in your tearDown method (or teardown_test_environment method - see below).
I am not sure if you are asking to find out how to do this. If so there are two ways that I can think of.
Use a common base class for all your tests. Something like this:
class TestBase(django.test.TestCase):
fixtures = ['common_fixtures.xml']
class MyTestClass(TestBase):
fixtures = TestBase.fixtures + ['fixtures_for_this_test.xml']
def test_foo(self):
# test stuff
Use a custom test runner. In your test runner load all the fixtures you need before running the tests and take them down after executing the tests. You should preferably do this by using your own setup_ and teardown_test_environment methods.