如何简化Pytest中同步与异步混合场景下的aiohttp链式Mock?
如何简化Pytest中同步与异步混合场景下的aiohttp链式Mock?
我完全懂你这种感受——写一堆中间mock变量不仅啰嗦得要命,还把你真正想做的事情(也就是mock出x的返回值)给淹没了,毕竟那些中间的session、resp对象你根本不在乎对吧?
其实你完全可以不用定义那些中间变量,直接用链式调用把整个mock逻辑串起来,一行代码就能搞定:
# 直接链式嵌套mock,不需要中间变量 mock_aiohttp.ClientSession.return_value.__aenter__.return_value.post.return_value.__aenter__.return_value.json.return_value = "ABC"
这里给你拆解一下链式逻辑,帮你理解为啥这么写就行:
ClientSession()是同步创建的,所以用return_value拿到session实例的mock;async with ... as session对应的是调用__aenter__()异步方法,所以用__aenter__.return_value拿到进入上下文后的session对象;session.post()是同步调用(返回一个异步上下文管理器),所以用post.return_value拿到这个上下文对象;async with ... as resp同理,用__aenter__.return_value拿到响应对象;resp.json()是异步方法,直接mock它的return_value就能得到你要的x的值。
如果觉得这一行太长可读性差,还可以把它拆成几行(用括号包裹),或者封装成一个辅助函数,让测试代码的意图更清晰:
def mock_aiohttp_post_json(mock_aiohttp, return_value): # 封装成函数,后续需要mock时直接调用 session = mock_aiohttp.ClientSession.return_value.__aenter__.return_value resp_context = session.post.return_value.__aenter__ resp_context.return_value.json.return_value = return_value # 调用时只要一行 mock_aiohttp_post_json(mock_aiohttp, "ABC")
要是你愿意引入第三方库,还有更省心的办法——用aioresponses这个专门针对aiohttp的mock库,它能帮你跳过手动mock ClientSession和上下文的繁琐步骤,直接mock HTTP请求的响应:
from aioresponses import aioresponses def test_your_async_function(): with aioresponses() as m: # 直接指定要mock的请求地址和返回内容 m.post("xyz.com", payload="ABC") # 这里直接调用你的业务逻辑函数即可,不用管底层的session mock # your_async_function()
这样不管是链式调用、封装函数还是用第三方库,都能帮你把那些冗余的mock代码砍掉,让测试代码更聚焦于你真正关心的业务逻辑~
备注:内容来源于stack exchange,提问作者Joe C.
相关产品推荐
相关产品推荐

