ExTexan
ExTexan

Reputation: 453

Django: How to get setUpTestData to run once for all tests?

I am running django + django_tenants + django_restframework. In the mulit-tenant environment, there needs to be an instance in the tenants table for each schema - in my testing, that means "public", "test", and "test2".

Creating those tenants, and their corresponding schemas, need to be created for all tests. The data in those instances will not change, so I want to do this once at the beginning of the test run, and not have it repeated again for the duration.

The things I've learned from my research:

The problem I've run into is, when my second set of tests run, I get exceptions when trying to create the tenants/schemas because they already exist.

I've also found setup_databases() in the Django advanced testing doc and am wondering if that is the place for this... i.e. can it be subclassed?

This is my base class that all tests subclass from...

class TenantTestCase(APITestCase):
    public_tenant = None
    test_tenant   = None
    test2_tenant  = None

    @classmethod
    def setUpClass(cls):
        cls.add_allowed_test_domain()
        cls.setUpTestData()

    @classmethod
    def setUpTestData(cls):
        print('run setUpTestData')

        cls.public_tenant = Tenant.create_tenant('Public')
        cls.test_tenant   = Tenant.create_tenant('Test')
        cls.test2_tenant  = Tenant.create_tenant('Test2')

        connection.set_tenant(cls.public_tenant)

I read that setUpTestData() is supposed to run before each test case (if subclassed from django.test.testcase), but it wasn't running in my case. I had to put cls.setUpTestData() in setUpClass() to get it to run.

This is a stripped-down example of one of my tests...

class TenantModelTests(TenantTestCase):

    def setUp(self):
        self.client = APIClient()
        super(TenantModelTests, self).setUp()

    def test_check_public_tenant(self):
        self.assertIsInstance(self.public_tenant, Tenant)

        self.assertEqual(self.public_tenant.name, 'Public', 'Public tenant name is not "Public".')
        self.assertEqual(self.public_tenant.subdomain, '', 'Public tenant subdomain is not blank.')
        self.assertEqual(self.public_tenant.schema_name, 'public', 'Public tenant schema_name is not "public".')

    def test_check_private_tenants(self):
        self.assertIsInstance(self.test_tenant, Tenant)

        self.assertEqual(self.test_tenant.name, 'Test', 'Test tenant name is not "Test".')
        self.assertEqual(self.test_tenant.subdomain, 'test', 'Test tenant subdomain is not "test".')
        self.assertEqual(self.test_tenant.schema_name, 'test', 'Test tenant schema_name is not "test".')

When I run this with two test files in two different apps, I see "run setUpTestData" twice - and, of course, I see the "already exist" exceptions. So where should I put code that should run once at the beginning of the entire test run?

Upvotes: 6

Views: 4789

Answers (1)

Kubas
Kubas

Reputation: 1028

setUpTestData is called is once for TestCase. In case databases does not support transactions, setUpTestData will be called before each test run.

Change your setUpClass and don't call setUpTestData directly. Try to user super()

@classmethod
def setUpClass(cls):
    cls.add_allowed_test_domain()
    super(TenantTestCase, cls).setUpClass()

Ref: https://docs.djangoproject.com/en/1.11/topics/testing/tools/#testcase Note that if the tests are run on a database with no transaction support (for instance, MySQL with the MyISAM engine), setUpTestData() will be called before each test, negating the speed benefits.

Upvotes: 3

Related Questions