Run Django tests against an existing database with custom testrunner - django

I've got an application that is running Django 2 that connects to a Microsoft SQL Server backend.
We're in a big environment where things are pretty tightly controlled - a user account has access to the database that houses all the tables for my django application.
So I have found through various posts that I need to create a testrunner for my application - which is fine. I can override the setup_databases function - but I'm not sure exactly how to do that.
My TestRunner(DiscoverRunner) looks like this:
class ExistingDbTestRunner(DiscoverRunner):
""" A test runner to test without database creation """
def setup_databases(self, **kwargs):
""" Override the database creation defined in parent class """
# force Django to connect to the correct db for tests
connection = self.connections['default']
db_conf = connection.settings_dict
connection.connect()
def teardown_databases(self, old_config, **kwargs):
""" Override the database teardown defined in parent class """
pass
But this fails with AttributeError: 'ExistingDbTestRunner' object has no attribute 'connections'
I'm just trying to get this to use the 'default' database that I have set in the settings for testing purposes.
It's worth noting - the default database specified in settings is a duplicate copy of the production database with a different name.
So I just want my tests to run against this duplicate database. What should I be changing so it connects?

Django tests do not operate on existing database or are meant to be used that way. Django always creates a new database, with the name test_db_name_specified_in_settings for all its tests.
More documentation can be found here: https://docs.djangoproject.com/en/2.0/topics/testing/overview/#the-test-database

Related

why records are not being inserted into postgresql database in pytest-django?

I tried to use postgres database with pytest-django and I've encountered a problem. I have a fixture named populate_db which creates some records in the database. To check if pytest actually creates records, I put a 60-seconds sleep after creating the model objects and checked the panel admin but none of the created objects were present there. I think the pytest can't connect to my database and doesn't create any records in the database. Below are the functions that I have in my conftest.py file and I have another test file which tries to retrieve a database record from the API.
Here is my code for the populate_db fixture:
#pytest.fixture(autouse=True)
def populate_db():
sport = Vertical.objects.create(name='sport')
bazar = Vertical.objects.create(name='bazar')
time.sleep(60)
yield

How to fix "Django test setUp() function not creating the django users"?

I am doing the django test cases. Now I have a problem that, user created in django test is not shown in the database created for test. consider my database name as db.
from django.contrib.auth.models import User,AnonymousUser
from django.test import TestCase,LiveServerTestCase
from django.db import connection
class machinelist(TestCase):
def setUp(self):
self.user=User.objects.create_user(username="vishnu***",email="vishnu#clartrum.com",password="vishnu#12345")
print self.user.username
db_name = connection.settings_dict['NAME']
print db_name
t=raw_input("PAUSE")
def tearDown(self):
print 'd'
def test1(self):#view function
print "2"
The output will print the username vishnu*** and db_name as test_db. But when you observe the database, there is no data.
In the code, when the raw_input is executed, I will sign into the mysql server and verified that test_db is created successfully and also the django's tables. But when i checked auth_user table there is no data in it.
I am using django 1.11.20 and mysql 5.6.33.
Why User is not updating on the database table?
Tests inside TestCase classes run in a transaction, which is rolled back at the end of each test. Since the default MySQL transaction isolation level is REPEATABLE READ, the data inserted within the transaction is not visible from outside.
I'm not sure why you want to check the data from outside the test, though. You can print it or assert on it from within the test itself.

How to prepopulate test database by necessary data?

I need to do some unit tests in my Django project. The problem is that almost every use case depends on prepopulated database objects.
For example, I want to create a product and test, if there were all pre_save signals successful.
from django.contrib.auth.models import User
from django.test import TestCase
from .models import Product
class ProductTestCase(TestCase):
def setUp(self):
self.user = User.objects.create(username='test_user')
self.product = Product.objects.create(name='Test product',user=self.user)
def test_product_exists(self):
self.assertIsNotNone(self.product)
def product_is_active_by_default(self):
...
I can't do that because product has to have User object related. But I can't create a User object because User has to have related plan object. There are multiple plans in my production database from which one is default but there are no plans inside test database.
So to be able to do unit tests I need to prepopulate test database with multiple objects from multiple apps.
How can I do that?
you can simply use django fixtures for that :-)
first populate a sample db with data then export data with python manage.py dumpdata
then in one of your apps create a directory named fixtures and put exported json file there (named tests.json or something else)
in your test class load fixtures like this
class ProductTestCase(TestCase):
fixtures = ['tests.json', ]
checkout django docs
PS: checkout factory boy too (#Gabriel Muj) answer
I don't recommend using fixture since you will need to maintain them each time you make changes to the model. Here is a better approach on creating objects for tests by using this library https://factoryboy.readthedocs.io/en/latest/ which is more flexible.

Django routing to database based on model table

I have a Django (1.6) project with two databases. I have one app with one model, and multiple tables.
I want to use the database routers to set specific tables in the model to a specific database. All the documentation I have found seems to explain how to route a particular app to a particular database.
Looks like you could use a custom router and model attribute for this.
YMMV: Haven't tested this.
https://docs.djangoproject.com/en/dev/topics/db/multi-db/#using-routers
class MyModel(models.Model):
_DATABASE = "foo"
class CustomRouter(object):
def db_for_read(self, model, **hints):
database = getattr(model, "_DATABASE", None)
return database
# repeat for db_for_write, etc.

Django - how to enable foreign keys in SqLite3 backend

When trying to use SqlLite3 as the DB backend to Django, I'd like to be able to use SqLite's Foreign Key support.
According to http://www.sqlite.org/foreignkeys.html, you can enable foreign key support by running:
PRAGMA foreign_keys = ON;
This support is disabled by default, and would be desirable while running most db dependent tests.
How would one control this feature while using Django test framework? Can you send backend-specific commands in your setUp/tearDown methods? Would you rather specify this option in connection settings ('DATABASE = ' settings) globally?
It's partially answered here: https://stackoverflow.com/a/6843142/552671.
You can just activate it in your app (typically in myapp/apps.py).
from django.db.backends.signals import connection_created
def activate_foreign_keys(sender, connection, **kwargs):
"""Enable integrity constraint with sqlite."""
if connection.vendor == 'sqlite':
cursor = connection.cursor()
cursor.execute('PRAGMA foreign_keys = ON;')
class MyAppConfig(AppConfig):
def ready(self):
connection_created.connect(activate_foreign_keys)
You have to configure MyAppConfig as well, write default_app_config = 'myapp.apps.PanelConfig' to myapp/__init__.py.
Note: This will activate foreign keys not only for tests but also SQLite in general. I think that is what you want, though.
In current django it is not needed anymore. Closed in https://code.djangoproject.com/ticket/14204
And from 2.2 it is also on during unit testing :)