Why object primary keys increment between tests in Django?
Asked Answered
A

2

9
class MyClassTest(TestCase):
    def setUp(self):
        Someclass.objects.create()

    def test_first_test(self):
        # Here, Someclass.objects.all()[0].pk -> returns 1

    def test_second_test(self):
       # Here, Someclass.objects.all()[0].pk -> returns 2 !!! (bad !)

With SetUp() method, the data is supposed to be cleared and recreated between each test. So, why ids increment from one test to another? It's not obvious to me.

This way I can't make tests based on ids (since they depends on other tests). That's why I'd like to get always 1 as result.

Note that I have no problem with the data itself, old data is well cleared from one test to another one. The problem is just about ids.

I read here django object ids increment between unit tests that the problem is related to the database, not to Django, but is there any trick in Django to change that?

Assignation answered 31/10, 2014 at 0:19 Comment(0)
C
4

You are very likely clearing the data, including the data in your database. That is not the same as recreating the database or recreating the sequences. If the sequences remain they will pick up where they left off.

Crosson answered 31/10, 2014 at 0:25 Comment(2)
I'm not sure to understand. I'm not clearing the data by myself, Django does it for me between each test. And the data is actually cleared, the problem is just related to the ids.Assignation
Unless you are using fixtures (which overwrite specific IDs), the values may be deleted but the database still may use the successive IDs.Throwaway
T
11

There's a warning in the test documentation:

https://docs.djangoproject.com/en/dev/topics/testing/overview/

Warning 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.

Using unittest.TestCase avoids the cost of running each test in a transaction and flushing the database, but if your tests interact with the database their behavior will vary based on the order that the test runner executes them. This can lead to unit tests that pass when run in isolation but fail when run in a suite.

Are you using django.test.TestCase or unittest.TestCase?

If you need to maintain PK integrety it seems there's an option you can try:

https://docs.djangoproject.com/en/dev/topics/testing/advanced/#django.test.TransactionTestCase.reset_sequences

Setting reset_sequences = True on a TransactionTestCase will make sure sequences are always reset before the test run:

class TestsThatDependsOnPrimaryKeySequences(TransactionTestCase):
    reset_sequences = True

    def test_animal_pk(self):
        lion = Animal.objects.create(name="lion", sound="roar")
        # lion.pk is guaranteed to always be 1
        self.assertEqual(lion.pk, 1)

Since, django.test.LiveServerTestCase seems to subclass TransactionTestCase this probably should work for you.

Throwaway answered 31/10, 2014 at 0:24 Comment(2)
I'm using django.test.LiveServerTestCase (I guess it inherits from django.test.TestCase)Assignation
tks! it worked!Suggest
C
4

You are very likely clearing the data, including the data in your database. That is not the same as recreating the database or recreating the sequences. If the sequences remain they will pick up where they left off.

Crosson answered 31/10, 2014 at 0:25 Comment(2)
I'm not sure to understand. I'm not clearing the data by myself, Django does it for me between each test. And the data is actually cleared, the problem is just related to the ids.Assignation
Unless you are using fixtures (which overwrite specific IDs), the values may be deleted but the database still may use the successive IDs.Throwaway

© 2022 - 2024 — McMap. All rights reserved.