【问题标题】:Setting up pymysql to work with django, pytest and pytest-django设置 pymysql 以使用 django、pytest 和 pytest-django
【发布时间】:2018-12-23 08:04:19
【问题描述】:

我有一个 Django 网站以及基于 pytestpytest-django 包的测试。我希望将 PyMySQL 包与我的设置一起用于测试和生产。

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

import pymysql
pymysql.install_as_MySQLdb()

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

这包括将 sn-p 放在 conftest.py:pytest_configure 中,在我的 django 项目的 manage.py 文件中,等等。都不起作用。

我从 mysqlclient 切换到 PyMySQL 的原因是,一旦我在 .travis.yml 中包含以下内容,mysqlclient 似乎无法与 travis.org 一起使用:

addons:
  mariadb: '10.0'

为了使用 MariaDB 而不是普通的 MySQL。

让 travis 使用 python mysqlclient 包也可以解决我的问题,但是我也无法完成。

作为参考,this 是 PR 的 travis 工作,以防我错过了一些重要的事情。

【问题讨论】:

    标签: python django pytest pymysql pytest-django


    【解决方案1】:

    好吧,起初我认为这是不可能的,因为 pytest-django 已经在模块级别导入了很多 django 东西,而且你无法通过钩子插入自己来击败它——它们都是在插件之后执行的是通过入口点加载的,所以 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
    

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

    放弃pytest,使用manage.py test

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

    pytest-django 旨在与pytest 命令配合使用,但如果您确实需要与manage.py test 集成,您可以像这样创建一个简单的测试运行器:

    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)
    

    在你的 Django 设置中添加这个类的路径:

    TEST_RUNNER = 'my_project.runner.PytestTestRunner'
    

    并通过

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

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

    【讨论】:

    • 哇!这看起来很棒!非常感谢您提供详细的解决方案并经历了测试的所有麻烦
    • 很高兴我能帮上忙!顺便说一句,好问题。
    • 谢谢。我经常觉得我的大部分问题都没有答案。不过,我似乎无法强制 pymysql_hack 文件驻留在测试目录中。有什么快速的指示吗?
    • 对于 Python 3,这应该通过 -p tests.pymysql_hack 开箱即用,Python 3 将简单地将 tests 视为隐式命名空间包。但是,Python 2 中没有定义隐式命名空间包。我猜想适当的路径调整,比如PYTHONPATH=".:tests" pytest -p pymysql_hack ...,应该适用于 Python 2;如果没有,您可能需要将 tests 转换为跨 python 解决方案的包。
    • 酷。再次感谢!
    【解决方案2】:

    我可以通过添加解决同样的问题

    import pymysql
    
    pymysql.install_as_MySQLdb()
    

    到我的 python3.6/site-packages/pytest_django/init.py 文件

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-26
      相关资源
      最近更新 更多