2014-11-18 4 views
1

Мы пишем некоторые модульные тесты, чтобы утверждать, что в определенных точках внутри функций транзакция базы данных активна. Однако мы боремся, как точно утверждать это, кто-нибудь знает, как мы можем это сделать? Просмотр Django Transaction Docs и Source Code for django.db.transaction не принесли ничего полезного.Django Unit Test Assert Database 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() 

Одно замечание: Мы действительно заинтересованы, чтобы сделать это в базе данных агностиком образом (мы используем SQLite в разработчика и PostgreSQL в другом месте), однако, если есть решения, которые работают только для postgresql, тогда это будет работоспособным.

ответ

0

Нам удалось достичь этого, добавив следующую функцию в тестовый класс.

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 - потому что это оборачивает каждый тест в транзакция, утверждение никогда не потерпит неудачу.