我有一个用于从另一个服务中获取信息的对象,这非常简单。由于对象很简单并且初始化方法很容易打补丁,我想我会尝试将代码编写为超级可重用和可扩展的。但是,a,我无法弄清楚如何使其工作。下面的代码是非常好的sudo代码,并且经过了超级简化,但应该可以理解这一点。
class SimpleClient:
def __init__(self):
pass
def read(self, key, path='some/path'):
return value_from_get_on_another_service
然后我有一个请求处理程序对象,该对象通过get_client()初始化客户端(如下所示)
def get_client():
return SimpleClient()
然后,请求处理程序上的方法使用client.read()方法几次并使用不同的参数(第二个取决于第一个)。
对于我的测试,我认为我可以“修补” get_client方法以返回自己的简单对象,然后可以“常规”使用该对象,从而消除了对第三方服务的依赖,并实际上使用了从方法执行中检索到的值。我很失望地发现它不是那么容易和干净。测试模式如下所示。
class MockClient:
def __init__(self, addr='someAddr', token='someToken'):
pass
def read(self, value, prefix):
data = {}
if prefix == 'path/1':
data = self.p1_lookup(value)
elif prefix == 'path/2':
data = self.p2_lookup(value)
return self.response_wrapper(data)
def p2_lookup(self, key):
data = {
'key1': {
'sub_key': {"55B3FE7D-9F43-4DD4-9090-9D89330C918A": "Dev2",
"7A1C2F4B-E91C-4659-A33E-1B18B0BEE2B3": "Dev"}
}
}
return data.get(key, {})
@mock.patch('a.module.get_client')
def test_authorize_valid_request_no_body(mock_get_client):
request = RequestMock()
request.body = None
handler = RequestHandler(Application(), request=request, logging_level='INFO')
mock_get_client.return_value = MockClient()
handler.authorize_request()
assert handler.verified_headers is None
assert handler.verified_body is None
assert handler.user_authenticated is False
我已经看到我可以在哪里模拟实际client.read()的响应以返回带有列表的多个值。但这似乎就像我将要进行大量复制和粘贴,并且每次小测试都要一遍又一遍地做同样的事情。如果这很简单,请原谅我,可悲的是我只是在学习测试的技巧。有没有办法完成我想做的事情?也许有些超级简单的东西我不见了。或者,也许我没有充分的理由就完全走错了路。帮助吗?!
答案 0 :(得分:1)
睡着后,新鲜的眼睛使我能够相对较快地解决这个问题,这要归功于我之前从未发现过的其他两个类似的问题/答案。主要是这个Python Mock Object with Method called Multiple Times。
不需要完全重建模块对象,我需要让模拟为我自己做,然后使用side_effect属性覆盖其上的特定方法。因此,下面是经过清理的代码版本。
def read_override(value, prefix):
lookup_data1 = {"lookup1": {'key1': 'value1'}}
lookup_data2 = {'some_id': {'akey': {'12345678': 'DEV'}}
data = {}
if prefix == 'path1/1a':
data = lookup_data1.get(value, {})
elif prefix == 'path2/2a':
data = lookup_data2.get(value, {})
return {'data': data}
# Create a true Mock of the entire LookupClient Object
VAULT_MOCK = mock.Mock(spec=LookupClient)
# make the read method work the way I want it to with an "override" of sorts
VAULT_MOCK.read.side_effect = vault_read_override
然后测试看起来像这样...
@mock.patch('a.module.get_client')
def test_authorize_valid_request_no_body(get_client):
get_client.return_value = VAULT_MOCK
request = RequestMock()
request.body = None
handler = RequestHandler(Application(), request=request, logging_level='INFO')
handler.authorize_request()
assert handler.verified_headers is None
assert handler.verified_body is None
assert handler.user_authenticated is False