我正在尝试使用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.py
中add_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}"