为什么Django中对象主键在测试间递增?
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 !)
在SetUp()
这个方法里,数据应该在每个测试之间被清空并重新创建。可是,为什么每次测试的ID会从一个增加到另一个呢?我觉得这不太明显。
这样一来,我就没办法根据ID来做测试,因为这些ID是依赖于其他测试的。所以我希望每次都能得到1
作为结果。
需要注意的是,我对数据本身没有问题,旧的数据在每个测试之间都能很好地清除。问题只是出在ID上。
我在这里看到一篇文章,提到这个问题和数据库有关,而不是Django本身,但在Django里有没有什么办法可以改变这个情况呢?
2 个回答
在测试文档中有一个警告:
https://docs.djangoproject.com/en/dev/topics/testing/overview/
警告:如果你的测试需要访问数据库,比如创建或查询模型,确保你的测试类是从
django.test.TestCase
继承的,而不是unittest.TestCase
。使用
unittest.TestCase
可以避免每个测试都在一个事务中运行并清空数据库的开销,但如果你的测试与数据库有交互,它们的行为会根据测试运行的顺序而变化。这可能导致一些单元测试在单独运行时通过,但在一起运行时却失败。
你是使用 django.test.TestCase
还是 unittest.TestCase
呢?
如果你需要保持主键的完整性,似乎有一个选项可以尝试:
在 TransactionTestCase
中设置 reset_sequences = True
可以确保在测试运行之前序列总是被重置:
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)
因为 django.test.LiveServerTestCase
似乎是从 TransactionTestCase
继承的,所以这应该对你有效。
你很可能是在清除数据,包括你数据库里的数据。这和重新创建数据库或者重新创建序列是两回事。如果序列还在,它们会从上次停止的地方继续。