【问题标题】:Mock an entire python module for django testcases为 django 测试用例模拟整个 python 模块
【发布时间】:2019-01-24 10:52:35
【问题描述】:

我目前正在尝试使用管道中的 Gitlab Runner 运行测试期间 不存在 的凭据.py 模块(凭据位于 .gitignore 上)。所以实际上“模拟”必须创建credentials.py。

编辑:我猜问题是 django 系统检查 (https://docs.djangoproject.com/en/2.1/ref/checks/),它检查是否所有导入都可用。

EDIT2:我找到了一种在测试环境中防止 import_error 的方法。但我不确定这是否是在编写好代码方面的选择,这就是我没有使用 answer-function 的原因。我发现了以下 stackoverflow 问题:Python: Mock a module without importing it or needing it to exist 并使用第一个答案中的建议来更改我在views.py 中的代码:

try:
   from battery_upgrade_web import credentials
except ImportError:
   from battery_upgrade_web import credentials_example as credentials

credentials_example 存在于 Gitlab 中并且为空。这样就可以在 Gitlab Runner 中成功进行所有测试。

我的test_views.py 看起来像这样:

@patch('battery_upgrade_web.views.BatteryUpgradeView.credentials', new=credentials_example)
class IndexViewTest(TestCase):

    @patch('battery_upgrade_web.views.BatteryUpgradeView.credentials', new=credentials_example)
    def setUp(self):
        # A client simulates a user interacting with the code at the view level
        # Lot of working mocks
        self.c = Client()

    @patch('battery_upgrade_web.views.credentials', new=credentials_example)
    def test_valid_data(self):
        resp = self.c.post('/', data={'parameter': 324})

我的views.py

from battery_upgrade_web import credentials

class BatteryUpgradeView(generic.TemplateView):
    def post(self, request, *args, **kwargs):
    #lot of code to execute

我的问题是,我不能只修补credentials.py 中的变量,而是必须修补整个模块并将其替换为credentials_example.py。我上面的解决方案在本地与现有的 credentials.py 一起工作,它还模拟了 credentials.py 并在测试期间用我的 credentials_example.py 替换它。但是当我删除 credentials.py 时,运行>python web/manage.py test battery_upgrade_web 时测试会抛出以下错误消息:

Creating test database for alias 'default'...
Traceback (most recent call last):
File "web/manage.py", line 16, in <module>
    execute_from_command_line(sys.argv)
    # lot of tracebacks
File "C:\Users\e\AppData\Local\Continuum\anaconda2\envs\BatteryUpgrade36\lib\importlib\__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 994, in _gcd_import
File "<frozen importlib._bootstrap>", line 971, in _find_and_loal
File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 678, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "C:\Users\e\Projects\BatteryUpgrade\web\battery_upgrade_web\urls.py", line 21, in <module>
from battery_upgrade_web.views import BatteryUpgradeView
File "C:\Users\e\Projects\BatteryUpgrade\web\battery_upgrade_web\views.py", line 11, in <module>
from battery_upgrade_web import credentials
ImportError: cannot import name 'credentials'

看起来,在测试正常开始之前有一个模块的导入。但是如何模拟呢?

【问题讨论】:

  • 为什么投反对票(谁给的)?请添加评论。这个问题表述得很好,问题陈述很清楚。

标签: python django unit-testing mocking


【解决方案1】:

我可以给你一个工作方向:

def setUp(self):
    model_mocked = MagicMock()
    model_mocked.credentials.return_value = {}
    modules = {'battery_upgrade_web': model_mocked}
    patch.dict('sys.modules', modules).start()

这将创建一个 MagicMock 添加凭据对象并将其添加到您可以导入的模块列表 (sys.modules) 中。

不确定它是否对你有用,但是这样做的方法。

【讨论】:

  • 感谢您的帮助 MaximeK。我实施了您的解决方案,但如果删除了 credentials.py,仍然会出现相同的错误。似乎 django 系统检查 (docs.djangoproject.com/en/2.1/topics/checks) 在检查所有导入是否正确时会引发错误。
  • 你可以模拟检查功能吗?
  • 好主意,但问题是,即使在 setUp() 函数中的代码执行之前,错误也会被抛出。我通过在setUp() 的开头设置pdb.set_trace() 来检查这一点 - 直到错误出现,代码执行才会停止。
猜你喜欢
  • 1970-01-01
  • 2015-11-11
  • 2016-08-24
  • 2017-05-04
  • 1970-01-01
  • 2019-08-16
  • 1970-01-01
  • 2021-08-27
  • 1970-01-01
相关资源
最近更新 更多