在Django测试中,TestCase类和TransactionTestCase类的区别

7 浏览
0 Comments

在Django测试中,TestCase类和TransactionTestCase类的区别

请解释一下TestCase类和TransactionTestCase类之间的区别。我已经阅读了文档,但只是说TestCase在数据库事务中运行测试,并使用回滚来“撤销”数据库中的测试,如果您需要在测试中手动管理事务,则需要使用django.test.TransactionTestCase

请帮我通过一个例子来理解实际的区别。

在什么情况下TestCase会失败?回滚是否会自动发生,还是我们需要编写代码来进行回滚?

0
0 Comments

Django框架中的TestCase和TransactionTestCase类之间的主要区别是,TestCase类始终在测试中使用atomic()块进行包装。根据文档的说法,TestCase会在整个类和每个测试中都使用两个嵌套的atomic()块。因此,如果有一个方法在没有包装在atomic()块中时应该引发错误,那么使用TestCase编写的测试将会意外地失败。

为了解决这个问题,可以使用TransactionTestCase类来编写测试,这样测试就可以通过了。TransactionTestCase类允许在测试中使用select_for_update()等需要在事务中执行的代码块。

在Django的文档中,还提到了select_for_update()方法在TestCase中的行为。通常情况下,在autocommit模式下调用select_for_update()方法会导致TransactionManagementError错误。然而,在TestCase中,即使在没有atomic()块的情况下调用select_for_update()方法,也不会引发TransactionManagementError错误。为了正确测试select_for_update()方法,应该使用TransactionTestCase类。

总结起来,如果需要测试需要在事务中执行的代码块,应该使用TransactionTestCase类。而如果不需要在事务中执行代码块,或者想要测试不需要在事务中执行的代码块,可以使用TestCase类。

希望这篇文章能帮助你理解TestCase和TransactionTestCase类之间的区别和使用方法。

0
0 Comments

Django中的TestCase和TransactionTestCase类的区别

在Django的测试框架中,有两个常用的测试类:TestCase和TransactionTestCase。这两个类都是从SimpleTestCase类继承而来,但它们有一些不同之处。

TestCase类在运行测试时会检查当前的数据库是否支持事务功能。如果支持,TestCase会创建一个事务块,并将所有的测试代码放在这个事务块中。在测试结束时,TestCase会回滚所有的事务,以保持数据库的干净状态。下面是setUp()和tearDown()函数的代码示例:

def setUpClass(cls):
    super(TestCase, cls).setUpClass()
    if not connections_support_transactions():
        return
    cls.cls_atomics = cls._enter_atomics()
    if cls.fixtures:
        for db_name in cls._databases_names(include_mirrors=False):
            try:
                call_command('loaddata', *cls.fixtures, **{
                    'verbosity': 0,
                    'commit': False,
                    'database': db_name,
                })
            except Exception:
                cls._rollback_atomics(cls.cls_atomics)
                raise
    cls.setUpTestData()
def tearDownClass(cls):
    if connections_support_transactions():
        cls._rollback_atomics(cls.cls_atomics)
        for conn in connections.all():
            conn.close()
    super(TestCase, cls).tearDownClass()

然而,TransactionTestCase类不会启动事务,它只会在所有测试完成后刷新数据库。下面是_post_teardown()和_fixture_teardown()函数的代码示例:

def _post_teardown(self):
    try:
        self._fixture_teardown()
        super(TransactionTestCase, self)._post_teardown()
        if self._should_reload_connections():
            for conn in connections.all():
                conn.close()
    finally:
        if self.available_apps is not None:
            apps.unset_available_apps()
            setting_changed.send(sender=settings._wrapped.__class__,
                                 setting='INSTALLED_APPS',
                                 value=settings.INSTALLED_APPS,
                                 enter=False)
def _fixture_teardown(self):
    for db_name in self._databases_names(include_mirrors=False):
        call_command('flush', verbosity=0, interactive=False,
                     database=db_name, reset_sequences=False,
                     allow_cascade=self.available_apps is not None,
                     inhibit_post_migrate=self.available_apps is not None)

下面是一个使用官方文档中的select_for_update()函数的简单示例:

class SampleTestCase(TestCase):
    def setUp(self):
        Sample.objects.create(**{'field1': 'value1', 'field2': 'value2'})
    
    def test_difference_testcase(self):
        sample = Sample.objects.select_for_update().filter()
        print(sample)
class SampleTransactionTestCase(TransactionTestCase):
    def setUp(self):
        Sample.objects.create(**{'field1': 'value1', 'field2': 'value2'})
    
    def test_difference_transactiontestcase(self):
        sample = Sample.objects.select_for_update().filter()
        print(sample)

第一个示例会引发AssertionError: TransactionManagementError not raised的错误,而第二个示例则不会出现错误。

这是因为TestCase类在测试过程中会创建事务,并在测试结束时回滚事务,因此在使用select_for_update()函数时会引发TransactionManagementError错误。而TransactionTestCase类不会创建事务,因此可以正常使用select_for_update()函数。

解决这个问题的方法是根据测试的需求选择合适的测试类。如果测试需要使用事务来保持数据库的一致性,可以使用TestCase类。如果测试不需要使用事务,或者需要测试事务相关的功能,可以使用TransactionTestCase类。

总结起来,TestCase类会自动创建事务并回滚事务,而TransactionTestCase类不会创建事务,需要手动管理数据库的一致性。根据测试的需求选择合适的测试类可以避免不必要的错误和麻烦。

0