【问题标题】:TransactionManagementError While Executing Unittest in Django Rest Framework在 Django Rest Framework 中执行单元测试时出现 TransactionManagementError
【发布时间】:2016-05-18 13:44:23
【问题描述】:

我已经编写了一个测试来检查是否在数据库中出现重复记录的情况下引发了 IntegrityError。为了创建那个场景,我发出了两次 REST API。代码如下所示:

class TestPost(APITestCase):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        common.add_users()

    def tearDown(self):
        super().tearDown()
        self.client.logout()

    def test_duplicate_record(self):
        # first time
        response = self.client.post('/api/v1/trees/', dict(alias="some name", path="some path"))
        # same request second time
        response = self.client.post('/api/v1/trees/', dict(alias="some name", path="some path"))
        self.assertEqual(response.status_code, status.HTTP_400_BAD_RREQUEST)

但是我得到一个像这样的错误堆栈

 "An error occurred in the current transaction. You can't "
django.db.transaction.TransactionManagementError: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.

我怎样才能避免这个错误,这当然是不可取的。

【问题讨论】:

  • 请显示完整的回溯。

标签: django django-rest-framework django-testing


【解决方案1】:

我今天遇到了这个问题,我花了一段时间才看到大局并正确解决它。确实,删除self.client.logout() 可以解决问题,并且可能不需要那里,但问题在于您的观点。

作为TestCase 子类的测试将您的测试用例和测试包装在数据库事务(原子块)中,您的视图会以某种方式破坏该事务。对我来说,它正在吞噬IntegrityError 异常。那时,事务已经被破坏了,但 Django 并不知道它,所以它不能正确地执行回滚。然后执行的任何查询都会导致TransactionManagementError

对我来说,解决方法是将视图代码正确地包装在另一个原子块中:

try:
    with transaction.atomic():  # savepoint which will be rolled back
        counter.save()  # the operation which is expected to throw an IntegrityError
except IntegrityError:
    pass  # swallow the exception without breaking the transaction

如果您不使用ATOMIC_REQUESTS,这对您在生产中可能不是问题,但我仍然认为这是正确的解决方案。

【讨论】:

  • ATOMIC_REQUESTS 的什么原因会在生产中造成问题?
  • @AndrewKonoff ATOMIC_REQUESTS 将整个视图包装在一个事务中,这在视图执行过程中发生崩溃时可能非常有用。但它也会创建与测试相同的场景。
【解决方案2】:

尝试从tearDown 方法中删除self.client.logout()。 Django 在每次测试结束时回滚事务。您不必手动注销。

【讨论】:

  • 哇!删除注销后问题已解决。您能否帮助我理解,“事务”首先出现在哪里以及为什么删除“注销”实际上解决了它。我认为 test.APITestCase 做的比我想象的要多。
  • 您的一项测试发生错误。然后,您在 teardown 方法中调用了self.client.logout()。这是不可能的,因为出现错误后无法在事务中执行查询。
猜你喜欢
  • 2018-05-14
  • 1970-01-01
  • 2015-06-04
  • 2016-09-07
  • 1970-01-01
  • 1970-01-01
  • 2020-05-03
  • 2020-08-04
  • 2014-12-07
相关资源
最近更新 更多