`
Xorcerer
  • 浏览: 35278 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

从Django 1.0.4 升级到1.1.1,部分UnitTest不通过的原因。

阅读更多
先说结论:
Django 1.1.1 为了提高UnitTest的执行速度,新增了一个TransationTestCase,而原来的Django 1.0.4 中的TestCase(下面用TestCase104和TestCase111来标示不同版本的TestCase)变成了TransactionTestCase的子类。
注意,TestCase111的执行速度较快,而不是TransactionTestCase,原因下面解释。

如果你的测试在1.0.4没问题,在1.1.1失败,那么试试使用TransactionTestCase。

失败的例子:
1、用户登录(无论是测试用的client.login,还是直接通过登录页面post数据);
2、访问某个view,带有登录校验的(如@login_required);
此时也许会报告未登录。

原因概述:
TestCase111屏蔽了方法内部的事务处理,而在方法首尾包裹一层事务,用于回滚在测试方法执行过程中修改的数据。
当你登录用户时,提示登录成功,之后,数据库链接可能会断开,此时由于事务被屏蔽,无法在断开前commit,此时数据库自动调用了rollback,导致刚才登录的信息丢失(比如保存到数据库的session信息)。访问view时,自然无法找到对应的登录信息。

原因详述:
原来TestCase104的一个测试方法执行完毕之后,框架就会自动调用一次flush命令,具体的数据库命令就是
BEGIN;
TRUNCATE "app1_table1", "app2_table1",......;

SELECT setval('"app1_table1_id_seq"', 1, false);
.......
COMMIT; 

这里列举的是PostgreSQL的SQL。

那么一个测试方法的执行过程就是:
1、加载测试数据(如果有的话);
2、运行测试;
3、清除数据库。

而在TestCase111中,flush命令被屏蔽了,取而代之的是,使用了事务的回滚操作来做同样的事情。
那么测试方法的执行过程被简化为被简化为:
1、运行测试;
2、回滚。

而在整个类的第一次实例化时,加载测试数据一次;全部方法执行完毕后,清除数据库。

这样做的好处自不待言,坏处是,在TestCase的方法中,如果用到事务,那么你的测试将出现异常。因为,方法中的事务都被屏蔽了,具体方法可以看django.test.testcases.py的源码,注意这一段:
real_commit = transaction.commit
real_rollback = transaction.rollback
real_enter_transaction_management = transaction.enter_transaction_management
real_leave_transaction_management = transaction.leave_transaction_management
real_savepoint_commit = transaction.savepoint_commit
real_savepoint_rollback = transaction.savepoint_rollback
real_managed = transaction.managed

def nop(*args, **kwargs):
    return

def disable_transaction_methods(): #事务方法都被替换为nop。
    transaction.commit = nop
    transaction.rollback = nop
    transaction.savepoint_commit = nop
    transaction.savepoint_rollback = nop
    transaction.enter_transaction_management = nop
    transaction.leave_transaction_management = nop
    transaction.managed = nop

def restore_transaction_methods(): #恢复事务方法。
    transaction.commit = real_commit
    transaction.rollback = real_rollback
    transaction.savepoint_commit = real_savepoint_commit
    transaction.savepoint_rollback = real_savepoint_rollback
    transaction.enter_transaction_management = real_enter_transaction_management
    transaction.leave_transaction_management = real_leave_transaction_management
    transaction.managed = real_managed


还有这一段:
class TestCase(TransactionTestCase):
    """
    Does basically the same as TransactionTestCase, but surrounds every test
    with a transaction, monkey-patches the real transaction management routines to
    do nothing, and rollsback the test transaction at the end of the test. You have
    to use TransactionTestCase, if you need transaction management inside a test.
    """

    def _fixture_setup(self):
        if not settings.DATABASE_SUPPORTS_TRANSACTIONS:
            return super(TestCase, self)._fixture_setup()

        transaction.enter_transaction_management()
        transaction.managed(True)
        disable_transaction_methods() #禁用事务。

        from django.contrib.sites.models import Site
        Site.objects.clear_cache()

        if hasattr(self, 'fixtures'):
            call_command('loaddata', *self.fixtures, **{
                                                        'verbosity': 0,
                                                        'commit': False
                                                        })

    def _fixture_teardown(self):
        print 'teardown'
        if not settings.DATABASE_SUPPORTS_TRANSACTIONS:
            return super(TestCase, self)._fixture_teardown()

        restore_transaction_methods() #恢复事务。
        transaction.rollback()
        transaction.leave_transaction_management()
        connection.close()


在一个测试方法跟数据库交互的过程中,会多次关闭和创建链接,这是,如果使用了事务,那么关闭链接之前,会有一次commit操作,但是这个操作在TestCase111中被屏蔽了,所以,数据库自行运行了rollback。这就是问题所在。

我们来看看数据库log的输出:
LOG:  duration: 0.209 ms  statement: UPDATE "django_session" SET "session_data" = E'gAJ9cQEoVQp0ZXN0Y29va2llcQJVBndvcmtlZHEDVQ1zaG9wX2NhcnRfa2V5cQRVIDMyYTA4NmQ0
	OGJiZDA5ZGU2MTBiMTg1NmVmMTI1MGM0cQVVEl9hdXRoX3VzZXJfYmFja2VuZHEGVStmb29qaWFf
	d2ViLmRqY29tLmF1dGguYmFja2VuZHMuRW1haWxCYWNrZW5kcQdVDV9hdXRoX3VzZXJfaWRxCEsB
	dS5iM2RjMjhlODVjNTNiOWRhYjFkNDFmMDQ0NmVmNGY2MQ==
	', "expire_date" = E'2010-01-19 23:47:10.886173' WHERE "django_session"."session_key" = E'60c11789a08805fa662ae4a9aabb5d16' 
LOG:  duration: 0.320 ms  statement: ROLLBACK
LOG:  disconnection: session time: 0:00:00.050 user=myweb database=test_myweb host=127.0.0.1 port=58286
LOG:  connection received: host=127.0.0.1 port=58287
LOG:  connection authorized: user=myweb database=test_myweb

这里可以看到,断开链接前,rollback了。
而如果用了TransactionTestCase,就会出现正常的Commit操作,然后再断开。

什么情况下会用到事务?
我在实际测试中发现,其实,包括存储session之类的操作,都需要事务的支持。
除非你测试的内容,是纯读,或者纯写之类的,否则的话,请注意一下TestCase/TransactionTestCase的选择。
分享到:
评论

相关推荐

    PyPI 官网下载 | django-woordeboek-1.1.1.tar.gz

    通过下载“django-woordeboek-1.1.1.tar.gz”,开发者可以将这个库集成到自己的项目中,提升应用的国际化水平,提高用户满意度。在实际开发过程中,结合官方文档和社区资源,可以进一步探索和挖掘这个库的潜力,让多...

    基于python3+django+requests+ddt+unittest的接口自动化测试平台源码+项目说明.zip

    【资源说明】 1、该资源包括项目的全部源码,下载可以直接使用! 2、本项目适合作为计算机、数学、电子信息等专业的课程设计、期末...基于python3+django+requests+ddt+unittest的接口自动化测试平台源码+项目说明.zip

    Python库 | django_snakeoil-1.1.1-py3-none-any.whl

    综上所述,"django_snakeoil-1.1.1-py3-none-any.whl" 是一个针对Python 3的Django扩展库,通过使用它可以为你的Django项目添加特定功能。安装和使用这个轮子文件能够简化流程,提升开发效率。在实际操作中,应了解...

    PyPI 官网下载 | django_leafage-1.1.1-py3-none-any.whl

    综上所述,django_leafage是一个与Django框架兼容的Python库,版本1.1.1,适用于Python 3环境,可以通过PyPI官方渠道获取,并以Wheel格式提供,便于快速部署到各种平台。这个库可能包含对Django框架的扩展功能或特定...

    PyPI 官网下载 | stream-django-1.0.4.tar.gz

    **PyPI 官网下载 | stream-django-1.0.4.tar.gz** 在Python的世界里,`PyPI`(Python Package Index)是官方的软件仓库,它为开发者提供了存储和分享他们创建的Python模块的地方。`stream-django-1.0.4.tar.gz`是一...

    Python库 | jsl_django_sitemap-1.1.1-py3-none-any.whl

    `jsl_django_sitemap-1.1.1-py3-none-any.whl` 是一个针对Python和Django框架的库,主要用于构建站点地图(Sitemaps)。在本文中,我们将深入探讨这个库的功能、用途以及如何在Django项目中使用它。 1. **Python与...

    Python库 | django-watson-1.1.1.tar.gz

    **Python库 django-watson-1.1.1.tar.gz** `django-watson` 是一个基于Python的全文搜索引擎库,特别为Django框架设计,用于帮助开发者在Django项目中实现高效、灵活的搜索功能。它利用了SQL查询来实现搜索,无需...

    Python库 | django_guid-1.1.1-py3-none-any.whl

    资源分类:Python库 所属语言:Python 使用前提:需要解压 资源全名:django_guid-1.1.1-py3-none-any.whl 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059

    Django 1.1.1

    在实际使用中,你可以通过解压下载的`Django-1.1.1`压缩包,按照官方文档的指引安装和配置Django环境。之后,你可以开始创建你的第一个Django项目,定义模型,编写视图,设计模板,并通过URL配置将它们连接起来。...

    Django-1.1.1.tar 包

    Django-1.1.1.tar 是一个针对Python Web框架Django的压缩包,版本号为1.1.1。这个版本的发布日期是2009年,它提供了开发Web应用所需的基本组件和功能。Django是一个开源的、基于模型-视图-控制器(MVC)架构模式的...

    Python库 | django-health-check-1.1.1.tar.gz

    `django-health-check-1.1.1` 提供了对 Django 应用全面的健康检查,是保障服务稳定性不可或缺的工具。通过集成这个库,开发者可以轻松地监控应用的运行状况,及时发现和解决可能的问题,提高系统的可靠性。在生产...

    PyPI 官网下载 | django-octicons-v10-1.1.1.tar.gz

    资源全名:django-octicons-v10-1.1.1.tar.gz" 进一步确认了这个资源的确是从PyPI官方获取的,并提供了完整的文件名,与标题信息一致。 **标签解析** 标签 "django python 后端 开发语言 Python库" 为我们的讨论...

    PythonWeb开发-Django从入门到精通(薯条老师)中文PDF高清版最新版本

    Python Web开发是一个Django从入门到精通,通过本系列的教程学习,可以学习到Django的mvc架构,models、views、templates、forms、session等的相关入门知识,学完本系列之后对django的入门知识有了比较深入的学习,...

    PyPI 官网下载 | flake8_django-1.1.1-py3-none-any.whl

    "PyPI 官网下载 | flake8_django-1.1.1-py3-none-any.whl" 这个标题表明这是一个从Python Package Index(PyPI)官方源下载的软件包。flake8_django是该软件包的名称,版本号为1.1.1,py3表示它兼容Python 3版本,...

    PyPI 官网下载 | django-helpful-1.0.4.tar.gz

    这个资源`django-helpful-1.0.4.tar.gz`就是从PyPI上下载的一个Python库,名为`django-helpful`,版本号为1.0.4。这个压缩包遵循了Python中常见的打包格式,通常包含源代码、元数据和可能的其他资源文件。 **Python...

Global site tag (gtag.js) - Google Analytics