Djangoユニットテストクラス-TestCaseとTransactionTestCase

3837 ワード

TestCaseとTransactionTestCaseはいずれもSimpleTestCaseから継承されており、両者の主な違いは:
  • TestCaseはテスト開始時に、現在接続されているデータベースがトランザクション特性をサポートしているかどうかを判断し、サポートされている場合はトランザクション操作を開始する.テストの終了時にも、サポートなどのトランザクションプロパティがサポートされているかどうかを判断し、トランザクションロールバックを実行し、すべてのリンクを閉じます.具体的なsetuUpClassとtearDownClassの方法は以下の
  • である.
    @classmethod
        def setUpClass(cls):
            super(TestCase, cls).setUpClass()
            if not connections_support_transactions():  #  
                return
            cls.cls_atomics = cls._enter_atomics()  #  ,TestCase Block 
    
            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()
    
    
    @classmethod
    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はTestCaseとは異なり、このテストクラスではトランザクションブロックは開かれず、テスト終了時にFush操作でデータをクリアします.このようなSimpleTestCaseを書き換えていないsetupとtearDownの方法は、変更されただけです.post_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)
    

    トランザクションの違いにより、TestCaseを使用する場合、テストされたコードにトランザクションブロックで実行する必要があるコードが表示されると、公式の例の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)
    

    最初のTestCaseは例外を放出します.
    AssertionError: TransactionManagementError not raised
    

    2番目のTTCはテストに合格します.

    小結

  • TestCaseは、後続のコードが1つの外部トランザクションのBlock内で実行されることに相当するため、テスト者は、トランザクションBlockで実行する必要があるコード(For instance,you cannot test that a block of code is executing within a transaction,as is required when using select_for_update()
  • をテストすることはできません.
  • TestCaseでは、最終トランザクションをロールバックする必要があるため、conn.close()のようなテストコードの操作を行うと、例外が発生します.
  • TransactionTestCaseはトランザクションを開始せず、テスト終了時のFlush DBのシナリオによってクリーン環境
  • を復元する.