我的情况与此类似:
import unittest
import requests_mock
import requests
import mock
class ClassUnderTest:
def __init__(self):
self.session = requests.Session()
self.foo_url = 'http://google.com'
def do_foo(self):
return self.session.get(self.foo_url)
def do_foo_failing(self):
# I want to prevent accidentally doing this sort of operation
# instead of reusuing self.session
return requests.get(self.foo_url)
我想确保方法正确执行,但也确保我使用self.session
对象。在实践中,我遇到了这个问题,因为我错误地添加了requests.get
来电而不是重新使用相同的会话。
然而,这意味着这样的测试实际上并未测试此功能:
class TestClassUnderTest(unittest.TestCase):
@requests_mock.mock()
def test_do_foo_should_pass(self, m):
c = ClassUnderTest()
m.get('http://google.com', status_code=200)
r = c.do_foo()
self.assertEqual(200, r.status_code)
self.assertEqual(m.call_count, 1)
@requests_mock.mock()
def test_do_foo_should_fail(self, m):
c = ClassUnderTest()
m.get('http://google.com', status_code=200)
r = c.do_foo_failing()
self.assertEqual(200, r.status_code)
self.assertEqual(m.call_count, 1)
我已经考虑用模拟替换self.session
,但是我还必须在模拟上设置status_code之类的东西(在我的实际代码示例中我还需要做一些事情,比如添加模拟{{} 3}}以便消耗响应的代码正确运行)。
有没有办法使用requests_mock有效保证只使用self.session
(在本例中不是requests.get
)?
答案 0 :(得分:1)
以下工作方法是将所有request.Session
函数包装到MockClass中,并使用包装器跟踪它们的使用情况:
class MockSession:
def __init__(self):
self.session = requests.Session()
self._called_methods = {}
def session_decorator(f):
def func(*args, **kwargs):
if f.__name__ not in self._called_methods:
self._called_methods[f.__name__] = 1
else:
self._called_methods[f.__name__] += 1
return f(*args, **kwargs)
return func
for name, f in inspect.getmembers(self.session):
if inspect.ismethod(f):
setattr(self, name, session_decorator(f))
使用此模拟后,您可以访问._called_methods
值以检查调用各个方法的频率。请注意,由于requests_mock的工作方式,您必须在运行时执行此操作(而不是通过简单地扩展具有类似功能的requests.Session类来加载时间。)
修改测试代码会导致:
class TestClassUnderTest(unittest.TestCase):
@requests_mock.mock()
def test_do_foo_should_pass(self, m):
c = ClassUnderTest()
c.session = MockSession()
m.get('http://google.com', status_code=200)
r = c.do_foo()
self.assertEqual(200, r.status_code)
self.assertEqual(m.call_count, 1)
self.assertEqual(c.session._called_count['GET'], 1)
@requests_mock.mock()
def test_do_foo_should_fail(self, m):
c = ClassUnderTest()
c.session = MockSession()
m.get('http://google.com', status_code=200)
r = c.do_foo_failing()
self.assertEqual(200, r.status_code)
self.assertEqual(m.call_count, 1)
# This will fail with an attribute error
# because that function was never invoked on the mock session
self.assertEqual(c.session._called_count['GET'], 1)