Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django TestCase: recreate database in self.subTest(...)

I need to test a function with different parameters, and the most proper way for this seems to be using the with self.subTest(...) context manager.

However, the function writes something to the db, and it ends up in an inconsistent state. I can delete the things I write, but it would be cleaner if I could recreate the whole db completely. Is there a way to do that?

like image 645
Ibolit Avatar asked Sep 07 '17 14:09

Ibolit


1 Answers

Not sure how to recreate the database in self.subTest() but I have another technique I am currently using which might be of interest to you. You can use fixtures to create a "snapshot" of your database which will basically be copied in a second database used only for testing purposes. I currently use this method to test code on a big project I'm working on at work.

I'll post some example code to give you an idea of what this will look like in practice, but you might have to do some extra research to tailor the code to your needs (I've added links to guide you).

The process is rather straighforward. You would be creating a copy of your database with only the data needed by using fixtures, which will be stored in a .yaml file and accessed only by your test unit.

Here is what the process would look like:

  1. List item you want to copy to your test database to populate it using fixtures. This will only create a db with the needed data instead of stupidly copying the entire db. It will be stored in a .yaml file.

generate.py

    django.setup()
    stdout = sys.stdout

    conf = [
        {
            'file': 'myfile.yaml',
            'models': [
                dict(model='your.model', pks='your, primary, keys'),
                dict(model='your.model', pks='your, primary, keys')
            ]
        }
    ]

    for fixture in conf:
        print('Processing: %s' % fixture['file'])
        with open(fixture['file'], 'w') as f:
            sys.stdout = FixtureAnonymiser(f)

        for model in fixture['models']:
            call_command('dumpdata', model.pop('model'), format='yaml',indent=4, **model)
            sys.stdout.flush()

        sys.stdout = stdout
  1. In your test unit, import your generated .yaml file as a fixture and your test will automatically use this the data from the fixture to carry out the tests, keeping your main database untouched.

test_class.py

from django.test import TestCase

class classTest(TestCase):

    fixtures = ('myfile.yaml',)

    def setUp(self):
        """setup tests cases"""
       # create the object you want to test here, which will use data from the fixtures

    def test_function(self):
        self.assertEqual(True,True)
        # write your test here

You can read up more here:

  • Django
  • YAML

If you have any questions because things are unclear just ask, I'd be happy to help you out.

like image 84
Adam Jaamour Avatar answered Oct 31 '22 21:10

Adam Jaamour