Skip to main content
 首页 » 编程设计

python之设置 pymysql 以与 django、pytest 和 pytest-django 一起工作

2024年09月07日39lidabo

我建立了一个 Django 网站以及基于 pytest 和 pytest-django 包的测试。我希望获得 PyMySQL 包以配合我的测试和生产设置。

我知道为了让 PyMySQL 将自己暴露为 mysqldb 模块以便 django(和其他模块)可以使用它 我应该将以下代码片段放在代码的开头。

import pymysql 
pymysql.install_as_MySQLdb() 

我多次尝试在我的代码中的不同位置调用上述函数,但 pytest 似乎没有足够早地检测到。

这包括将代码片段放在 conftest.py:pytest_configure 中,放在我的 django 项目的 manage.py 文件中,等等。都没有用。

我从 mysqlclient 切换到 PyMySQL 的原因是 mysqlclient 在我使用 travis.org 后似乎无法正常工作在 .travis.yml 中包含以下内容:

addons: 
  mariadb: '10.0' 

为了使用 MariaDB 而不是 vanilla MySQL。

让 travis 与 python mysqlclient 包一起工作也将解决我的问题,但我也无法完成。

供引用,this是 PR 的 travis 工作,以防我错过一些重要的事情。

请您参考如下方法:

好吧,起初我认为这是不可能的,因为 pytest-django 已经在模块级别导入了很多 django 的东西,你无法通过通过钩子(Hook)插入你自己 - 它们都是在插件通过入口点加载后执行的,因此 django 届时将已经导入。

但是,查看 pytest --help,注意一个很少使用的选项,它在这种情况下很有用:

$ pytest --help 
... 
test session debugging and configuration: 
  -p name               early-load given plugin (multi-allowed). To avoid 
                        loading of plugins, use the `no:` prefix, e.g. 
                        `no:doctest`. 

通过插件早期加载运行pymysql配置

因此通过 -p arg 传递的自定义插件将比通过入口点加载的插件更早导入。解决方案现在很简单:编写一个导入和配置 pymysql 的小模块,并通过 -p arg 传递它:

# rematch/pymysql_hack.py 
import pymysql 
pymysql.install_as_MySQLdb() 

测试调用:

$ PYTHONPATH=. pytest -p pymysql_hack -rapP server tests/server 

我 fork 了 rematch 项目来测试它,the jobs are looking good (第一个作业失败是因为我懒得在所有需求文件中添加pymysql)。

放弃pytest,使用manage.py test

或者(这是我的第一个解决方案建议),您可以通过 manage.py 运行测试,因此您可以在 之上添加 pymysql 配置行manage.py,实现自定义测试运行器,如 pytest-django's FAQ 中所述:

pytest-django is designed to work with the pytest command, but if you really need integration with manage.py test, you can create a simple test runner like this:

class PytestTestRunner(object): 
    """Runs pytest to discover and run tests.""" 
 
    def __init__(self, verbosity=1, failfast=False, keepdb=False, **kwargs): 
        self.verbosity = verbosity 
        self.failfast = failfast 
        self.keepdb = keepdb 
 
    def run_tests(self, test_labels): 
        """Run pytest and return the exitcode. 
 
        It translates some of Django's test command option to pytest's. 
        """ 
        import pytest 
 
        argv = [] 
        if self.verbosity == 0: 
            argv.append('--quiet') 
        if self.verbosity == 2: 
            argv.append('--verbose') 
        if self.verbosity == 3: 
            argv.append('-vv') 
        if self.failfast: 
            argv.append('--exitfirst') 
        if self.keepdb: 
            argv.append('--reuse-db') 
 
        argv.extend(test_labels) 
        return pytest.main(argv) 

Add the path to this class in your Django settings:

TEST_RUNNER = 'my_project.runner.PytestTestRunner' 

并通过

调用测试
$ python manage.py test <django args> -- <pytest args> 

但是,您将无法使用此解决方案通过直接调用 pytest 来运行测试。