我们正在编写一些单元测试来声明在函数内的某些点处存在一个活动的数据库事务。然而,我们正在努力如何确切地断言这一点,有谁知道我们如何做到这一点?浏览Django Transaction Docs和Source Code for django.db.transaction并未发现任何有用的内容。
以下是一些代码,用于说明我们尝试实现的目标,使用Assertion Injection:
def function_under_test():
... some stuff ....
function_we_will_patch_to_assert_transaction_is_open()
... some more stuff ...
class MyTestCase(TestCase):
def assert_transaction_is_active(self):
self.assertTrue(...what goes in here to assert this?...)
@patch('function_we_will_patch_to_assert_transaction_is_open'):
def test_function_under_test__transaction_is_active(self, patched_fn):
patched_fn.side_effect = self.assert_transaction_is_active
function_under_test()
一个注意事项:我们非常希望以数据库无关的方式执行此操作(我们在dev中使用sqlite,在其他地方使用postgresql),但是如果有解决方案仅适用于postgresql,那么这将是可行的。
答案 0 :(得分:1)
我们通过向测试类添加以下函数来实现此目的。
def assert_inside_atomic_block(self, using=None):
"""
Returns a function that will assert we are inside an atomic transaction block. The purpose of this is to allow
us to inject this assertion inside methods where we want to verify that a transaction is active.
Does not work with django.db.TransactionTestCase because it automatically wraps each test in a transaction.
"""
if issubclass(self.__class__, TransactionTestCase):
raise AssertionError('Cannot determine if code is run inside a transaction with a TransactionTestCase')
def _assert_inside_atomic_block(*args, **kwargs):
if not get_connection(using=using).in_atomic_block:
raise AssertionError('Not inside an atomic transaction block')
return _assert_inside_atomic_block
然后可以在测试中使用以下内容:
@patch('function_we_will_patch_to_assert_transaction_is_open'):
def test_function_under_test__transaction_is_active(self, patched_fn):
patched_fn.side_effect = self.assert_inside_atomic_block()
function_under_test()
需要注意的一点是:这种技术不适用于基于django.test.TransactionTestCase
的测试类 - 因为这包含了事务中的每个测试,断言永远不会失败。