解决unittest.TestCase异步测试中RuntimeWarning协程未等待错误
我在运行异步unittest测试时遇到问题,示例代码如下:
import unittest import asyncio from asyncio import coroutine import pytest import os class TestEcommerce(unittest.TestCase): async def assertFloatAlmostEqual(self, first, second, places=2, msg=""): """ 用于按指定精度比较浮点数值。 每次测试得到的数值精度可能略有差异,但这不属于错误 :param msg: :param first: :param second: :param places: :return: """ self.assertAlmostEqual(first, second, places=places, msg=msg) @pytest.mark.asyncio async def test_deep_analysis_find_complex(self): # 示例代码 await self.assertFloatAlmostEqual(100.44, 100.445) pass
运行后报错:
kernel/test/test_demo.py::TestEcommerce::test_deep_analysis_find_complex
/usr/lib/python3.10/unittest/case.py:549: RuntimeWarning: coroutine 'TestEcommerce.test_deep_analysis_find_complex' was never awaited
method() Enable tracemalloc to get traceback where the object was allocated.-- Docs: pytest警告捕获相关文档
我试过查看同类问题但解决方案无效,还尝试移除测试函数的async关键字,出现预期内的语法错误:
修改后的代码:
@pytest.mark.asyncio def test_deep_analysis_find_complex(self): # 示例代码 await self.assertFloatAlmostEqual(100.44, 100.445) pass
对应错误:
E await self.assertFloatAlmostEqual(100.44, 100.445)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E SyntaxError: 'await' outside async function
我的环境信息:
执行pip list --format=freeze | grep pytest输出:
pytest7.4.0
pytest-asyncio0.21.1
执行python -V输出:
Python 3.10.6
问题原因
混用unittest.TestCase类与pytest-asyncio的@pytest.mark.asyncio装饰器,unittest.TestCase的测试方法不兼容该装饰器的异步调度逻辑,导致协程未被正确执行。
解决方法
方案1:改用pytest原生测试类(不继承unittest.TestCase)
将测试类改为普通类,无需继承unittest.TestCase,让pytest-asyncio正常处理异步测试:
import pytest class TestEcommerce: def assertFloatAlmostEqual(self, first, second, places=2, msg=""): # 无需async,直接实现近似断言 assert abs(first - second) < 10**(-places), msg or f"{first} 与 {second} 在{places}位精度下不相等" # 也可直接用pytest内置断言: # assert first == pytest.approx(second, rel=10**(-places)) @pytest.mark.asyncio async def test_deep_analysis_find_complex(self): # 断言方法非协程,无需await self.assertFloatAlmostEqual(100.44, 100.445)
方案2:保留unittest.TestCase,用asyncio.run手动执行协程
如果必须继承unittest.TestCase,可在普通测试方法内定义异步逻辑并通过asyncio.run执行:
import unittest import asyncio class TestEcommerce(unittest.TestCase): def assertFloatAlmostEqual(self, first, second, places=2, msg=""): self.assertAlmostEqual(first, second, places=places, msg=msg) def test_deep_analysis_find_complex(self): async def async_test_logic(): # 这里可放入真正的异步操作 self.assertFloatAlmostEqual(100.44, 100.445) asyncio.run(async_test_logic())
额外提示
你的assertFloatAlmostEqual方法本身没有异步操作,完全不需要定义为async方法——只有包含异步调用(如await其他协程)的方法才需要设为协程,避免不必要的await操作。
内容的提问来源于stack exchange,提问作者stas stas

