在使用 pytest 时在装饰器中模拟对象
Posted
技术标签:
【中文标题】在使用 pytest 时在装饰器中模拟对象【英文标题】:mocking objects within a decorator while using pytest 【发布时间】:2020-07-30 04:27:07 【问题描述】:在下面的例子中,我有一个装饰器。在装饰器中,我正在实例化一个数据库连接类。我在下面有一个测试类,我想在装饰器中模拟数据库连接类。我该怎么做?
# importing libraries
import time
import math
# decorator to calculate duration
# taken by any function.
def calculate_time(func):
# added arguments inside the inner1,
# if function takes any arguments,
# can be added like this.
def inner1(*args, **kwargs):
db_conn = DBConn()
# storing time before function execution
begin = time.time()
func(*args, **kwargs)
# storing time after function execution
end = time.time()
db_conn.logTime(begin, end)
print("Total time taken in : ", func.__name__, end - begin)
return inner1
# this can be added to any function present,
# in this case to calculate a factorial
@calculate_time
def test_factorial(num):
# sleep 2 seconds because it takes very less time
# so that you can see the actual difference
time.sleep(2)
print(math.factorial(num))
# calling the function.
factorial(10)
【问题讨论】:
db_conn = new DBConn()
。这看起来像一个语法错误。 DBConn()
也没有定义。如何实例化对象对于如何模拟它很重要。
@jordanm 抱歉,这是一个错字。 DBConn() 是我在此处添加的示例,以了解如何模拟它。
取决于它的定义/导入方式
@jordanm 该功能按预期工作。但是,我想创建一个模拟类,而不是 DConn 创建一个实际的类。一般来说,我使用装饰器补丁(packagename.DBConn)来修补它。但是由于它是一个装饰器,我不确定如何将补丁装饰器与 calculate_time 装饰器结合起来
应该像导入一样被模拟,例如@patch('<module_with_calculate_time>.DBConn')
,前提是它像 from xxx import DBConn
一样导入。由于装饰师,这里没有什么特别的。如果您将如何导入 DBConn
添加到您的问题中会有所帮助。
【参考方案1】:
好的,为了更清楚:
假设您的模块位于包 mypackage
中,并且带有装饰器的模块 calculate_time.py
看起来像:
from mypackage.dbconn import DBConn
def calculate_time(func):
def inner1(*args, **kwargs):
...
你有 factorial.py
的模块:
from mypackage.calculate_time import calculate_time
@calculate_time
def factorial(num):
time.sleep(2)
print(math.factorial(num))
那么您的测试可能如下所示:
from unittest.mock import patch
from mypackage.factorial import factorial
class FakeConn:
def logTime(self, begin, end):
print(begin, end)
@patch('mypackage.calculate_time.DBConn', new=FakeConn)
def test_factorial():
print(factorial(10))
【讨论】:
以上是关于在使用 pytest 时在装饰器中模拟对象的主要内容,如果未能解决你的问题,请参考以下文章
如何在具有模拟装饰器的测试中使用 pytest capsys?
我们可以将装饰对象的实例设为私有而不是在抽象装饰器中保护吗?