[英]Unit test failing when mocking python3
我正在尝试模拟 python3 requests
这是我的单元测试:
from source.automation.my_web_session import MyWebSession
from unittest.mock import patch
@patch('requests.Session', autospec=True)
def test_initialize_session(mock_session):
# Arrange
user_agent = 'mobile user agent'
mock_session.headers = {'user-agent' : user_agent}
csrftoken = 'csrftoken'
mock_session.cookies = {'csrftoken' : csrftoken}
my_web_session = MyWebSession()
# Act
print(my_web_session.session.cookies)
# Assert
assert my_web_session.session.cookies['csrftoken'] == csrftoken
这是我正在测试的课程:
import requests
class MyWebSession:
def __init__(self):
self.session = requests.Session()
我正在尝试模拟用户代理的设置和更新。 但是,运行我的测试时出现以下错误:
================================== FAILURES ===================================
___________________________ test_initialize_session ___________________________
mock_session = <MagicMock name='Session' spec='Session' id='81084944'>
@patch('requests.Session', autospec=True)
def test_initialize_session(mock_session):
# Arrange
user_agent = 'mobile user agent'
mock_session.headers = {'user-agent' : user_agent}
csrftoken = 'csrftoken'
mock_session.cookies = {'csrftoken' : csrftoken}
my_web_session = MyWebSession()
# Act
> print(my_web_session.session.cookies)
my_web_session_test.py:14:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <NonCallableMagicMock name='Session()' spec='Session' id='80148752'>
name = 'cookies'
def __getattr__(self, name):
if name in {'_mock_methods', '_mock_unsafe'}:
raise AttributeError(name)
elif self._mock_methods is not None:
if name not in self._mock_methods or name in _all_magics:
> raise AttributeError("Mock object has no attribute %r" % name)
E AttributeError: Mock object has no attribute 'cookies'
我在这里做错了什么?
问题是您正在配置类( mock_session
替换Session
)但您想要配置实例,这是它的返回值。 你可以这样做,但它不会做一个很好的测试。 这对我有用:
@patch('requests.Session', autospec=True)
def test_initialize_session(mock_session_cls):
# Arrange
mock_session = Mock(spec=[])
user_agent = 'mobile user agent'
mock_session.headers = {'user-agent' : user_agent}
csrftoken = 'csrftoken'
mock_session.cookies = {'csrftoken' : csrftoken}
mock_session_cls.return_value = mock_session
my_web_session = MyWebSession()
# Act
print(my_web_session.session.cookies)
# Assert
assert my_web_session.session.cookies['csrftoken'] == csrftoken
有些人可能更喜欢下面的版本(我也不喜欢):
def test_initialize_session():
# Arrange
mock_session = Mock(spec=[])
user_agent = 'mobile user agent'
mock_session.headers = {'user-agent' : user_agent}
csrftoken = 'csrftoken'
mock_session.cookies = {'csrftoken' : csrftoken}
with patch('requests.Session', autospec=True, return_value=mock_session):
my_web_session = MyWebSession()
# Act
print(my_web_session.session.cookies)
# Assert
assert my_web_session.session.cookies['csrftoken'] == csrftoken
我觉得这个测试的丑陋之处在于,当您只对第二个感兴趣时,您正在对一个测试替身进行存根以返回另一个测试替身。 对我来说,这看起来像是太多的测试替身。
潜在的问题是Session
实例的创建作为实现细节隐藏在__init__
方法中,但您的测试想要像控制公共 API 一样控制它。 解决这种紧张的一种方法是在MyWebSession
之外创建Session
并将实例作为参数传递。 然后测试变得更加简单,你可以摆脱你并不真正感兴趣的补丁和测试替身。
class MyWebSession:
def __init__(self, session):
self.session = session
和测试:
def test_initialize_session():
# Arrange
user_agent = 'mobile user agent'
mock_session = Mock(spec=[])
mock_session.headers = {'user-agent' : user_agent}
csrftoken = 'csrftoken'
mock_session.cookies = {'csrftoken' : csrftoken}
my_web_session = MyWebSession(mock_session)
# Act
print(my_web_session.session.cookies)
# Assert
assert my_web_session.session.cookies['csrftoken'] == csrftoken
在生产代码中,您将使用类似
my_web_session = MyWebSession(requests.Session())
另一种方法是将MyWebSession
视为一个瘦包装器,为requests.Session
提供更方便的接口(如果这就是您在这里尝试做的),那么您可能会将测试视为特征测试,而根本不使用测试替身。
请注意, # Act
注释放错了位置,并且对print
的调用与测试无关(也许您将其放在那里进行调试?)。 这无济于事,但我将其保留在您的代码中,以尽可能少地偏离它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.