如何在单元测试中仅Mock被测代码的asyncio.sleep以加速测试?
解决仅Patch被测代码中asyncio.sleep的问题
问题根源:Python的标准库模块(比如asyncio)是单例模式,被测代码sut.py和测试代码test.py导入的是同一个asyncio对象。因此直接patch sut.asyncio.sleep会修改全局的asyncio.sleep,导致测试代码里的sleep也变成Mock实例,无法在测试逻辑中使用原生sleep实现快速延迟。
方案1:封装被测代码中的sleep(推荐)
在被测代码中封装独立的sleep函数,业务逻辑调用这个封装函数,测试时仅patch该封装函数,不会影响全局asyncio.sleep。
修改sut.py:
import asyncio # 封装sleep供业务代码调用 async def sleep(delay): await asyncio.sleep(delay) async def target_func(): # 业务逻辑中使用封装的sleep await sleep(10) # 其他业务代码...
测试代码test.py:
import asyncio import pytest from unittest.mock import patch import sut @pytest.mark.asyncio @patch("sut.sleep") async def test_fast_sleep(mock_sleep): # 定义快速sleep逻辑,使用原生asyncio.sleep async def fast_sleep(t): await asyncio.sleep(t / 10) mock_sleep.side_effect = fast_sleep # 执行被测函数 await sut.target_func() # 验证sleep调用参数 mock_sleep.assert_called_once_with(10)
方案2:不修改被测代码,保存原生sleep后全局Patch
如果无法改动被测代码,可在Patch前保存原生的asyncio.sleep,在side_effect中调用原生函数实现缩短延迟:
import asyncio import pytest from unittest.mock import patch import sut # 提前保存原生sleep函数 original_sleep = asyncio.sleep @pytest.mark.asyncio @patch("asyncio.sleep") async def test_fast_sleep_global(mock_sleep): async def fast_sleep(t): # 调用原生sleep,传入1/10的延迟 await original_sleep(t / 10) mock_sleep.side_effect = fast_sleep # 执行被测函数 await sut.target_func() # 验证调用断言 mock_sleep.assert_called_once_with(10)
注意:该方案会全局替换asyncio.sleep,测试代码中如果自行调用asyncio.sleep也会使用快速版本,需根据测试场景判断是否适用。
内容的提问来源于stack exchange,提问作者Joe C.
相关产品推荐
相关产品推荐

