python - 如何修补“autospec”设置为 True 的对象?
问题描述
我有以下玩具类:
class MyClass:
def __init__(self, x):
self.x = x
def get_operator(self):
answer = input("Multiply? ")
if answer == "y":
return "multiply"
def multiply(self, y):
if self.get_operator() == "multiply":
return self.x * y
以下测试(使用 pytest)将引发错误:
def test_multiply_is_called(mocker):
multiply = mocker.patch("package.module.MyClass.multiply", return_value=1, autospec=True)
my_instance = MyClass(2)
my_instance.multiply(3)
multiply.assert_called_once() # no error whatever autospec is equal to (True or False)
multiply.assert_called_with(3) # no error only if autospec=False
类型错误:不能将“autospec”与 create=True 一起使用
尝试模拟 Python 内置函数时,它变得更加模糊input
:
def test_input_is_called_once(mocker):
input = mocker.patch("package.module.input", return_value="y", autospec=True)
my_instance = MyClass(2)
my_instance.get_operator()
input.assert_called_once() # no error only if autospec=False
E AssertionError:未找到预期的调用。
E 预期:multiply(3)
E 实际:multiply(<package.module.MyClass object at 0x0000022A4BEEFD00>, 3)
我认为嘲笑autospec=True
是一种推荐的做法,但是,很明显,我对它的工作原理有一个错误的理解,尽管我已经阅读了这篇文章和这篇文章。
有人可以澄清这个问题吗?
解决方案
这实际上是两个不相关的问题。第一个问题源于这样一个事实,autospec=False
即调用my_instance.multiply(3)
只是归结为对带有参数 3 的模拟调用而没有任何检查(例如简单的函数调用)。但是,如果您使用autospec=True
,则该方法multiply
被绑定到my_instance
实际调用中,并作为方法调用,并my_instance
作为第一个 ( self
) 参数。所以要让它工作,你需要:
def test_multiply_is_called(mocker):
multiply = mocker.patch("package.module.MyClass.multiply", return_value=1, autospec=True)
my_instance = MyClass(2)
my_instance.multiply(3)
multiply.assert_called_with(my_instance, 3)
第二种情况不同,我不得不承认我并不完全清楚它是如何与autospec=False
. 问题是它input
没有绑定到模块,而是一个全局导入(from builtins
),因此它被创建为一个新的模拟对象,而不知道实际的内置函数。在这种情况下,autospec
由于缺少信息,将无法工作。这可以通过模拟内置函数来解决:
def test_input_is_called_once(mocker):
input = mocker.patch("builtins.input", return_value="y", autospec=True)
my_instance = MyClass(2)
my_instance.get_operator()
input.assert_called_once()
这适用于autospec=True
和autospec=False
。据我了解,autospec=False
它之所以有效,是因为为本地函数创建了一个模拟input
,然后在调用中实际使用它。从我的角度来看,模拟的正确方法input
是模拟builtins.input
,无论如何。
推荐阅读
- docker - 如何从 Docker-Composed C# 应用程序连接到本地 SQL Server Express 数据库?
- javascript - Nextjs 路由 - 捕获除公用文件夹之外的所有内容
- javascript - 单击按钮子元素时错误的 event.target
- rest - Cosmos DB REST API 授权标头不允许我替换文档
- postgresql - cloudsqladmin 保持 CloudSQL 实例始终开启?
- bootstrap-4 - 如何正确对齐一项并使用 Bootstrap 4 保持一项居中?
- amazon-web-services - 如何在 aws EKS 中管理 pod 调度?
- spartacus-storefront - Spartacus v3:从 v2 迁移后,无法从“付款详细信息”导航到“审核订单”
- reactjs - ag-grid vs Kendo React 网格的优缺点
- vue.js - 配置文件页面组件不会显示在带有 VueJS 路由的新路由器链接上