python - 避免在单元测试中运行顶级模块代码
问题描述
我正在尝试对一些导入模块的 Python 3 代码进行单元测试。不幸的是,模块的编写方式,简单地导入它会产生令人不快的副作用,这对测试并不重要。我正在尝试使用unitest.mock.patch
它来解决它,但运气不佳。
这是一个说明性示例的结构:
.
└── work
├── __init__.py
├── test_work.py
├── work.py
└── work_caller.py
__init__.py
是一个空文件
工作.py
import os
def work_on():
path = os.getcwd()
print(f"Working on {path}")
return path
def unpleasant_side_effect():
print("I am an unpleasant side effect of importing this module")
# Note that this is called simply by importing this file
unpleasant_side_effect()
work_caller.py
from work.work import work_on
class WorkCaller:
def call_work(self):
# Do important stuff that I want to test here
# This call I don't care about in the test, but it needs to be called
work_on()
测试工作.py
from unittest import TestCase, mock
from work.work_caller import WorkCaller
class TestWorkMockingModule(TestCase):
def test_workcaller(self):
with mock.patch("work.work.unpleasant_side_effect") as mocked_function:
sut = WorkCaller()
sut.call_work()
在work_caller.py
我只想测试开始代码,而不是调用work_on()
. 当我运行测试时,我得到以下输出:
paul-> python -m unittest
I am an unpleasant side effect of importing this module
Working on /Users/paul/src/patch-test
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
我期望该行I am an unpleasant side effect of importing this module
不会被打印,因为该函数unpleasant_side_effect
会被模拟。我可能哪里出错了?
解决方案
运行有unpleasant_side_effect
两个原因。首先,因为导入是在测试用例开始之前处理的,因此在导入时不会被模拟。其次,因为模拟本身会导入work.py
,因此unpleasant_side_effect
即使work_caller.py
没有导入也会运行。
导入问题可以通过模拟模块work.py
本身来解决。这可以在测试模块或测试用例本身中全局完成。这里我给它分配了一个MagicMock
,可以导入,调用等。
测试工作.py
from unittest import TestCase, mock
class TestWorkMockingModule(TestCase):
def test_workcaller(self):
import sys
sys.modules['work.work'] = mock.MagicMock()
from work.work_caller import WorkCaller
sut = WorkCaller()
sut.call_work()
缺点是 work_on 也被嘲笑,我不确定你的情况是否有问题。
导入时不可能不运行整个模块,因为函数和类也是语句,因此模块执行必须在返回到调用者之前完成,调用者想要更改导入的模块。
推荐阅读
- uwp - 在 UWP 中滚动期间 AutoSuggestBox 建议列表未关闭
- c# - 在排序中使用 ItemSource 和 ListViewItem
- delphi - GlobalFree - 不兼容的类型:“NativeUInt”和“PWideChar”
- python - Pandas groupby 丢弃列
- java - Maven - 从 JAR 文件加载资源?
- go - go中如何清除执行缓存
- kendo-ui - 使用 kendoNumericTextBox 的剑道模板
- git - 我无法与我的 Git 合作。git commit 和 git add 时出错,所以我什至无法完成我的任务
- azure - 如果 VM 代理状态未使用 Powershell 准备好,我们可以执行脚本自动重启服务吗?
- unity3d - 如何在瓷砖地图中更改单个瓷砖中的对撞机