Python模拟函数
unittest.mock 或Mock 函数是一个用于Python测试的库,它允许你用mock 对象替换被测系统的部件,并对这些部件的使用情况作出断言。
unittest.mock 给出了一个核心的Mock 类,消除了在你的测试套件中创建大量存根的必要性。
在执行一个过程后,你可以断言哪些方法或属性被使用,以及它们被调用的参数。你还可以指定返回值,并以通常的方式设置所需的属性。
此外,Mock 提供了一个patch() 装饰器,可以处理测试范围内的修补模块和类级属性,还有一个帮助器sentinel ,用于创建独特的对象。
Mock 洛克菲勒是为了与 一起使用而创建的,它基于 模式,而不是 ,后者被用于大多数嘲讽框架中。 有一个用于Python先前版本的回传。unittest action-to-assertion record-to-replay unittest.mock
设置和安装Pytest Mock
与unittest 相比,pytest 不是一个内置的Python包,需要安装。这可以通过在终端输入以下命令来安装。
pip install pytest
作为说明,unittest 的最佳实践也适用于pytest ,例如:
- 需要一个tests/ 目录来包含所有单元测试。
- 文件名必须总是以tests_ 开头。
- 函数名称必须总是以the test 开头。
命名标准必须被遵守,以便检查员可以找到所执行的单元测试。
在你使用pytest-mock 之前,需要安装它。下面是如何使用pip 来安装它:
pip install pytest-mock
这是一个Pytest的插件。因此,如果你还没有这样做,它将安装Pytest。
模拟一个函数
首先,创建一个简单的函数get_os() ,告诉我们是使用Windows还是Linux作为操作系统。
创建一个名为app.py 的文件,如下所示:
from time import sleep
def isWindows():
# This sleep can be some complex operation
sleep(5)
return True
def get_os():
return 'Windows is the current OS' if isWindows() else 'Linux is the current OS'
这个函数使用isWindows 函数来确定当前的操作系统是否是Windows。假设这个isWindows 函数相当复杂,需要几秒钟的时间来运行,这里我们可以模拟这个慢速运行的函数,每次调用它时,进入程序睡眠5秒钟。
下面将是一个get_os() 函数的pytest :
创建一个名为test_app.py 到pytest 的文件:
from app import get_os
def test_get_os():
assert get_os() == 'Windows is the current OS'
由于get_os() 调用了一个较慢的函数isWindows ,所以测试进行的很慢。这可以从下面执行pytest 的输出中看出。
它花了5.02秒,而且会因当前实例的不同而不同。
单元测试需要快速,我们应该能够在几秒钟内执行数百个测试。测试套件被一个耗时5秒的测试拖累了,所以应用嘲讽让我们的生活更轻松。
如果我们给慢速运行的函数打上补丁,我们就可以验证get_os() 函数的行为,而不必停留5秒钟。
让我们用pytest-mock 来模拟这个函数。
Pytest-mock 在Python的集成嘲弄结构之上,提供了一个叫做 的固定装置和一个精细的接口。你可以通过从它那里调用mock和patch函数,并将它们作为参数发送到你的测试函数,来采用一个mocker。mocker
在一个案例中,你想让isWindows 函数返回True ,而不需要等待那宝贵的5秒钟,我们可以对它进行修补,如下所示:
mocker.patch('app.isWindows', return_value=True)
在这里,你必须把isWindows 称为app.isWindows ,因为它是app 模块中的函数。如果我们只修补isWindows ,它将试图修补test_app 文件中的一个名为isWindows 的函数,而这个函数并不存在。
格式总是<module_name>.<function_name>
,知道如何正确的模拟是至关重要的。
下面描述了打完补丁后修改后的测试函数:
from app import get_os
# Python小白学习交流群:153708845
# using'mocker' fixture provided by pytest-mock
def test_get_os(mocker):
# mocking the slow-going function and returning True always
mocker.patch('app.isWindows', return_value=True)
assert get_os() == 'Windows is the current OS'
现在,当你运行这个测试时,它会更快地完成。
正如你所看到的,这个测试只花了0.02秒,所以我们成功地修补了慢速运行的函数,加速了测试套件的运行。
嘲讽的另一个好处是,你可以让嘲讽函数返回任何东西,甚至可以让它引发错误,以测试你的代码在这些情况下是如何处理的。
在这里,如果你想测试isWindows ,返回False 的情况,写出以下测试:
from app import get_os
def test_os_isLinux(mocker):
mocker.patch('app.isWindows', return_value=False) # set the return value to be False
assert get_os() == 'Linux is the current OS'
mocker附带的mock和patches都是函数范围的,这意味着它们只能用于那个特定的函数。因此,在不同的测试中,同一函数的补丁之间不会有任何冲突。
总结
嘲弄是用一个嘲弄来代替你正在测试的应用程序组件的做法,它是该组件的一个假实现。通过嘲弄,我们可以得到一些好处,如提高速度,测试运行速度快是非常有益的,在测试过程中避免不希望出现的副作用,等等。