unittest.mock.patch - 使用 pytest 模拟函数时"TypeError: 'str' object is not callable"



我正在尝试使用pytest为我的flask应用程序编写一些测试。我正在用unittest.mock.patch模拟一个函数。当使用@patch装饰器时,我似乎遇到了模拟函数不可调用的问题。

我没有展示我的flask代码,而是用下面一个简化的、人为的示例来演示我遇到的问题。

示例目录:

|-- outer.py
|-- util.py
|-- test_example.py

util.py:

import os
def getUsername():
user = os.getenv('username')   
return(user)

outer.py:

from util import getUsername
def add_user_age():
age = 111
user = getUsername()
return(f"{age}:{user}")
if __name__ == '__main__':
x = add_user_age()
print(x)

test_example.py:

from outer import add_user_age
from unittest.mock import patch 
@patch("outer.getUsername","JohnDoe")
def test_example():
s = add_user_age()
assert s == "111:JohnDoe"

输出:

============================= test session starts =============================
platform win32 -- Python 3.7.1, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:flaskpytest_concept, inifile:
plugins: remotedata-0.3.1, openfiles-0.3.1, doctestplus-0.2.0, arraydiff-0.3
collected 1 item
test_example.py F                                                        [100%]
================================== FAILURES ===================================
________________________________ test_example _________________________________
@patch("outer.getUsername","JohnDoe")
def test_example():
>       s = add_user_age()
test_example.py:6:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
def add_user_age():
age = 111
>       user = getUsername()
E       TypeError: 'str' object is not callable
outer.py:5: TypeError
========================== 1 failed in 0.06 seconds ===========================

这个想法是,我想模拟combine_age111_and_username中使用的getUsername函数。当我模拟它的时候,它说'str'对象是不可调用的;但是,如果我在add_user_age:

中做这样的更改outer.py(改变):

from util import getUsername
def add_user_age():
#...
user = getUsername # The change is right here, notice that I am not calling it
#...

测试将按预期通过:

C:flaskpytest_concept>python -m pytest
============================= test session starts =============================
platform win32 -- Python 3.7.1, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:flaskpytest_concept, inifile:
plugins: remotedata-0.3.1, openfiles-0.3.1, doctestplus-0.2.0, arraydiff-0.3
collected 1 item
test_example.py .                                                        [100%]
========================== 1 passed in 0.04 seconds ===========================
C:flaskpytest_concept>

但是,如果在pytest之外运行,该更改将使add_user_age返回不正确的结果,因为它将返回一个函数对象而不是当前登录的用户。我希望能够使用补丁装饰器,而不必改变outer.pyadd_user_age()的行为。

欢迎提出建议。由于

你可以给os.getenv打补丁:

from outer import add_user_age
import os
import contextlib
from unittest import mock

@contextlib.contextmanager
def fakeGetEnv(*args):
with mock.patch.object(
os, 'getenv', mock.Mock(wraps=os.getenv)
) as patched:
patched.return_value = args[0]
yield

def test_example():
expectedUser = 'JohnDoe'
with fakeGetEnv(expectedUser):
s = add_user_age()
assert s == f"111:{expectedUser}"

相关内容

最新更新