How do I run a test in Django using production data (Read only)?

Viewed 2993

I would like to run a test in Django but in order to run the test I need access to data from the production database (I don't want to setup an entirely new database for testing).

How can use this data from the production database without allowing write access in my script? I don't want this test to effect anything, but I need access to this data in order to run this test. It seems ridiculous to have to launch (and pay for) an entirely new database just to grab a few rows of data, any advice?

3 Answers

I would recommend against doing this. You will not have full control over the state of the database when running tests, and the passing of a test might depend on the contents of the production database. And it will be impossible to test edge cases before they occur. Not to mention that if you mess something up you run the risk of populating your production database with test data or destroying records from your production database.

Django makes creating test databases very simple. When using the command python manage.py test [app_name] a test database will be created for you with the same settings as your production/development database.

To get this functionality, the Django test docs state:

If your tests rely on database access such as creating or querying models, be sure to create your test classes as subclasses of django.test.TestCase rather than unittest.TestCase.

Here's more on the Django test database: https://docs.djangoproject.com/en/2.1/topics/testing/overview/#the-test-database

Regarding your concern about maintaining a test database, Django spins up the database before the tests are rune and destroys the database after the tests have finished. The test database is also created on your local machine (assuming you run it on your local machine). So I don't think pricing should be an issue.

Edit: On populating the test database before tests:

1. Create instances within a test before the test logic starts. These will be destroyed when the test finishes. Example:

class Tester(TestCase):
    def test_works(self):
        instance = Model.create(data=data)
        # then run your test logic

or

2. Create instances in the setUp method of a test class. Everything in setUp will be (re)created before each test method of the class and destroyed after each test completes. Example:

class Tester(TestCase):
    def setUp(self):
        self.instance = Model.create(data=data)

    def test_works(self):
        # run test logic with access to self.instance

or

3. Using fixtures to populate before tests are run. Define data for some instances of your Models in the fixtures directory within whatever app you're testing in (directory will probably need to be created). You can define them in json or yaml and I'm sure other formats. Then in your tests:

class Tester(TestCase):
    def setUp(self):
        fixtures = ['/myapp/fixtures/dump.json']

    def test_works(self):
        # test logic and you can access all the instances created from the data in dump.json

More on fixtures: https://django-testing-docs.readthedocs.io/en/latest/fixtures.html

If you want your test db to have data similar to your production database, you can pull data from the production database and save it in a fixture.

I agree with others that this is a bad idea for various reason. If you want to move forward with it anyway, set up a separate database user with read-only permissions. How you do this depends on the database server you are using.

Double check that you are actually using the credentials of the read-only user in your tests.

Don't do that. You must use the setUp of your test to construct your situation to test. Don't use fixtures also because you have to maintain them, in future you'll change your model and your fixtures must be updated too. This is very annoying.

If you do a good unit test you can mock your models and test the functions you want to test. I do that often when I want to test a method.

If you need you can create some utility function to help you setup the situation you need to create the models and related models to construct the env you want to test.

Related