携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情
fastapi执行一个同步的单元测试
- 在开发过程中,需要自己来编写一系列的单元测试,来保证自己编写的代码的质量
- 编写我们的第一个同步单元测试
import sys
sys.path.append('.')
import pytest
client = TestClient(bugmaker, base_url='http://127.0.0.1:9999')
class TestUser:
"""测试登录用例"""
@pytest.mark.parametrize('data', [{
"username": "Jack",
"password": "123456"
}])
def test_login(self, data):
"""测试登录"""
response = client.post(url="/oauth/Login", json=data)
res: dict = response.json()
assert response.status_code == 200
assert res.get('msg') == '登录成功'
assert res.get('detail') is not None and res.get('detail') != {}
# 执行单元测试只需要在命令行执行pytest即可
- 遇到的问题
- 如果你是使用view的注册依赖系统来实现的sqlalchemy的数据库session连接,那么你编写了多个测试用例会无法工作
# 错误信息
ERROR sqlalchemy.pool.impl.AsyncAdaptedQueuePool:base.py:249 Exception closing connection <AdaptedConnection <aiomysql.connection.Connection object at 0x000001A6AC5B83D0>>
Traceback (most recent call last):
File "D:\softtest_python_scripts\PlatForm\bug_maker\bugmaker\lib\site-packages\sqlalchemy\pool\base.py", line 739, in _finalize_fairy
fairy._reset(pool)
File "D:\softtest_python_scripts\PlatForm\bug_maker\bugmaker\lib\site-packages\sqlalchemy\pool\base.py", line 988, in _reset
pool._dialect.do_rollback(self)
File "D:\softtest_python_scripts\PlatForm\bug_maker\bugmaker\lib\site-packages\sqlalchemy\engine\default.py", line 682, in do_rollback
dbapi_connection.rollback()
File "D:\softtest_python_scripts\PlatForm\bug_maker\bugmaker\lib\site-packages\sqlalchemy\dialects\mysql\aiomysql.py", line 205, in rollback
self.await_(self._connection.rollback())
File "D:\softtest_python_scripts\PlatForm\bug_maker\bugmaker\lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 76, in await_only
return current.driver.switch(awaitable)
File "D:\softtest_python_scripts\PlatForm\bug_maker\bugmaker\lib\site-packages\sqlalchemy\util\_concurrency_py3k.py", line 129, in greenlet_spawn
value = await result
File "D:\softtest_python_scripts\PlatForm\bug_maker\bugmaker\lib\site-packages\aiomysql\connection.py", line 358, in rollback
await self._read_ok_packet()
File "D:\softtest_python_scripts\PlatForm\bug_maker\bugmaker\lib\site-packages\aiomysql\connection.py", line 331, in _read_ok_packet
pkt = await self._read_packet()
File "D:\softtest_python_scripts\PlatForm\bug_maker\bugmaker\lib\site-packages\aiomysql\connection.py", line 559, in _read_packet
packet_header = await self._read_bytes(4)
File "D:\softtest_python_scripts\PlatForm\bug_maker\bugmaker\lib\site-packages\aiomysql\connection.py", line 596, in _read_bytes
data = await self._reader.readexactly(num_bytes)
File "D:\soft\Python3.9\lib\asyncio\streams.py", line 723, in readexactly
await self._wait_for_data('readexactly')
File "D:\soft\Python3.9\lib\asyncio\streams.py", line 517, in _wait_for_data
await self._waiter
RuntimeError: Task <Task pending name='anyio.from_thread.BlockingPortal._call_func' coro=<BlockingPortal._call_func() running at D:\softtest_python_scripts\PlatForm\bug_maker\bugmaker\lib\site-packages\anyio\from_thread.py:187> cb=[TaskGroup._spawn.<locals>.task_done() at D:\softtest_python_scripts\PlatForm\bug_maker\bugmaker\lib\site-packages\anyio\_backends\_asyncio.py:629]> got Future <Future pending> attached to a different loop
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "D:\softtest_python_scripts\PlatForm\bug_maker\bugmaker\lib\site-packages\sqlalchemy\pool\base.py", line 247, in _close_connection
self._dialect.do_close(connection)
File "D:\softtest_python_scripts\PlatForm\bug_maker\bugmaker\lib\site-packages\sqlalchemy\engine\default.py", line 688, in do_close
dbapi_connection.close()
File "D:\softtest_python_scripts\PlatForm\bug_maker\bugmaker\lib\site-packages\sqlalchemy\dialects\mysql\aiomysql.py", line 212, in close
self._connection.close()
File "D:\softtest_python_scripts\PlatForm\bug_maker\bugmaker\lib\site-packages\aiomysql\connection.py", line 298, in close
self._writer.transport.close()
File "D:\soft\Python3.9\lib\asyncio\selector_events.py", line 700, in close
self._loop.call_soon(self._call_connection_lost, None)
File "D:\soft\Python3.9\lib\asyncio\base_events.py", line 746, in call_soon
self._check_closed()
File "D:\soft\Python3.9\lib\asyncio\base_events.py", line 510, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
- 解决方案在当前目录的conftest文件下新建TestClient和
# 修改设置优先循环事件
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
# 解决当接口中涉及依赖注入的数据库使用
async def start_db():
"""解决当接口中涉及依赖注入的数据库使用"""
async with async_engine.begin() as conn:
pass
await async_engine.dispose()
@pytest.fixture(scope="module")
def client() -> Generator:
"""客户端"""
with TestClient(app=bugmaker, base_url='http://127.0.0.1:9999') as cli:
# await start_db()
yield cli
# await async_engine.dispose()