开发者

Can Django flush its database(s) between every unit test?

Django (1.2 beta) will reset the database(s) between every test that runs, meaning each test runs on an empty DB. However, the database(s) are not flushed. One of the effects of flushing the database is the auto_increment counters are reset.

Consider a test which pulls data out of the database by primary key:

class ChangeLogTest(django.test.TestCase):
    def test_one(self):
        do_something_which_creates_two_log_entries()
        log = LogEntry.objects.get(id=1)
        assert_log_entry_correct(log)
        log = LogEntry.objects.get(id=2)
        assert_log_entry_correct(log)

This will pass because only two log entries were ever created. However, if another test is added to ChangeLogTest and it happens to run before test_one, the prim开发者_JAVA技巧ary keys of the log entries are no longer 1 and 2, they might be 2 and 3. Now test_one fails.

This is actually a two part question:

  1. Is it possible to force ./manage.py test to flush the database between each test case?
  2. Since Django doesn't flush the DB between each test by default, maybe there is a good reason. Does anyone know?


is it possible to force ./manage.py test to flush the database between each test case?

Have a look on the implementation of the command of django.core.management.commands.flush.py.

You can call the flush command from inside your test call (maybe in TestCase.setUp):

management.call_command('flush')

maybe there is a good reason. Does anyone know?

Yes there is: Speed up. Flushing and reloading many data from json takes a while...

Maybe you should have a look on TransactionTestCase


The answer to this is, don't write your tests in such a way as they depend on particular key values. For example, your test could better be written:

def test_one(self):
    do_something_which_creates_two_log_entries()
    logs = LogEntry.objects.all()
    assert_log_entry_correct(log[0])
    assert_log_entry_correct(log[1])


You can also use 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)


If you use any sort of "flush", keep in mind that if you've automated user creation or any other sort of data insert, it'll be deleted too.

An easy way to solve this problem without flushing is to get the ID of the first object during the test and increment from there.

Test1:
assertEqual(foo.id, 1)
assertEqual(bar.id, 2)

Test2:
start_id = Foo.objects.first().id
assertEqual(foo.id, start_id)
assertEqual(bar.id, (start_id + 1))
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜