修复坏枪从来没有运行过的单元测试,为项目引入单元测试框架(终于。。)
This commit is contained in:
6
.sqls.yml
Normal file
6
.sqls.yml
Normal file
@ -0,0 +1,6 @@
|
||||
lowercaseKeywords: false
|
||||
connections:
|
||||
- driver: sqlite
|
||||
dataSourceName: "./data/database.db"
|
||||
- driver: sqlite
|
||||
dataSourceName: "./data/perm.sqlite3"
|
||||
3
justfile
3
justfile
@ -1,4 +1,5 @@
|
||||
watch:
|
||||
poetry run watchfiles bot.main . --filter scripts.watch_filter.filter
|
||||
|
||||
|
||||
test:
|
||||
poetry run pytest
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
from contextlib import asynccontextmanager
|
||||
import os
|
||||
import asyncio
|
||||
import sqlparse
|
||||
@ -10,16 +11,19 @@ if TYPE_CHECKING:
|
||||
from . import DatabaseManager
|
||||
|
||||
# 全局数据库管理器实例
|
||||
_global_db_manager: Optional['DatabaseManager'] = None
|
||||
_global_db_manager: Optional["DatabaseManager"] = None
|
||||
|
||||
def get_global_db_manager() -> 'DatabaseManager':
|
||||
|
||||
def get_global_db_manager() -> "DatabaseManager":
|
||||
"""获取全局数据库管理器实例"""
|
||||
global _global_db_manager
|
||||
if _global_db_manager is None:
|
||||
from . import DatabaseManager
|
||||
|
||||
_global_db_manager = DatabaseManager()
|
||||
return _global_db_manager
|
||||
|
||||
|
||||
def close_global_db_manager() -> None:
|
||||
"""关闭全局数据库管理器实例"""
|
||||
global _global_db_manager
|
||||
@ -87,6 +91,12 @@ class DatabaseManager:
|
||||
except:
|
||||
pass
|
||||
|
||||
@asynccontextmanager
|
||||
async def get_conn(self):
|
||||
conn = await self._get_connection()
|
||||
yield conn
|
||||
await self._return_connection(conn)
|
||||
|
||||
async def query(
|
||||
self, query: str, params: Optional[tuple] = None
|
||||
) -> List[Dict[str, Any]]:
|
||||
@ -152,7 +162,9 @@ class DatabaseManager:
|
||||
return statements
|
||||
|
||||
async def execute_by_sql_file(
|
||||
self, file_path: Union[str, Path], params: Optional[Union[tuple, List[tuple]]] = None
|
||||
self,
|
||||
file_path: Union[str, Path],
|
||||
params: Optional[Union[tuple, List[tuple]]] = None,
|
||||
) -> None:
|
||||
"""从 SQL 文件中读取非查询语句并执行"""
|
||||
path = str(file_path) if isinstance(file_path, Path) else file_path
|
||||
@ -167,7 +179,9 @@ class DatabaseManager:
|
||||
# 使用sqlparse准确分割SQL语句
|
||||
statements = self._parse_sql_statements(script)
|
||||
if len(statements) != len(params):
|
||||
raise ValueError(f"语句数量({len(statements)})与参数组数量({len(params)})不匹配")
|
||||
raise ValueError(
|
||||
f"语句数量({len(statements)})与参数组数量({len(params)})不匹配"
|
||||
)
|
||||
|
||||
for statement, stmt_params in zip(statements, params):
|
||||
if statement:
|
||||
@ -215,4 +229,3 @@ class DatabaseManager:
|
||||
except:
|
||||
pass
|
||||
self._in_use.clear()
|
||||
|
||||
|
||||
2572
poetry.lock
generated
2572
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@ -34,6 +34,8 @@ dependencies = [
|
||||
"shapely (>=2.1.2,<3.0.0)",
|
||||
"mcstatus (>=12.2.1,<13.0.0)",
|
||||
"borax (>=4.1.3,<5.0.0)",
|
||||
"pytest (>=8.0.0,<9.0.0)",
|
||||
"nonebug (>=0.4.3,<0.5.0)",
|
||||
]
|
||||
|
||||
[tool.poetry]
|
||||
@ -52,8 +54,14 @@ priority = "primary"
|
||||
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"rust-just (>=1.43.0,<2.0.0)",
|
||||
"pytest (>=9.0.1,<10.0.0)",
|
||||
"pytest-asyncio (>=1.3.0,<2.0.0)"
|
||||
]
|
||||
dev = ["rust-just (>=1.43.0,<2.0.0)", "pytest-asyncio (>=1.3.0,<2.0.0)"]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = "tests"
|
||||
python_files = "test_*.py"
|
||||
asyncio_mode = "auto"
|
||||
asyncio_default_fixture_loop_scope = "session"
|
||||
|
||||
[tool.nonebot]
|
||||
# plugin_dirs = ["konabot/plugins/"]
|
||||
plugin_dirs = []
|
||||
|
||||
28
tests/conftest.py
Normal file
28
tests/conftest.py
Normal file
@ -0,0 +1,28 @@
|
||||
# 文件内容来源:
|
||||
# https://nonebot.dev/docs/best-practice/testing/
|
||||
# 保证 nonebug 测试框架正常运作
|
||||
|
||||
import pytest
|
||||
import nonebot
|
||||
from pytest_asyncio import is_async_test
|
||||
from nonebot.adapters.console import Adapter as ConsoleAdapter
|
||||
from nonebug import NONEBOT_START_LIFESPAN
|
||||
|
||||
|
||||
def pytest_collection_modifyitems(items: list[pytest.Item]):
|
||||
pytest_asyncio_tests = (item for item in items if is_async_test(item))
|
||||
session_scope_marker = pytest.mark.asyncio(loop_scope="session")
|
||||
for async_test in pytest_asyncio_tests:
|
||||
async_test.add_marker(session_scope_marker, append=False)
|
||||
|
||||
|
||||
@pytest.fixture(scope="session", autouse=True)
|
||||
async def after_nonebot_init(after_nonebot_init: None):
|
||||
driver = nonebot.get_driver()
|
||||
driver.register_adapter(ConsoleAdapter)
|
||||
|
||||
nonebot.load_from_toml("pyproject.toml")
|
||||
|
||||
|
||||
def pytest_configure(config: pytest.Config):
|
||||
config.stash[NONEBOT_START_LIFESPAN] = False
|
||||
@ -1,4 +1,3 @@
|
||||
import asyncio
|
||||
import os
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
@ -12,7 +11,7 @@ from konabot.common.database import DatabaseManager
|
||||
async def test_database_manager():
|
||||
"""测试数据库管理器的基本功能"""
|
||||
# 创建临时数据库文件
|
||||
with tempfile.NamedTemporaryFile(suffix='.db', delete=False) as tmp_file:
|
||||
with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as tmp_file:
|
||||
db_path = tmp_file.name
|
||||
|
||||
try:
|
||||
@ -42,8 +41,9 @@ async def test_database_manager():
|
||||
assert results[0]["email"] == "zhangsan@example.com"
|
||||
|
||||
# 测试使用Path对象
|
||||
results = await db_manager.query_by_sql_file(Path(__file__), ("李四",))
|
||||
# results = await db_manager.query_by_sql_file(Path(__file__), ("李四",))
|
||||
# 注意:这里只是测试参数传递,实际SQL文件内容不是有效的SQL
|
||||
## ^^^ 卧了个槽的坏枪,你让 AI 写单元测试不检查一下吗
|
||||
|
||||
# 关闭所有连接
|
||||
await db_manager.close_all_connections()
|
||||
@ -58,7 +58,7 @@ async def test_database_manager():
|
||||
async def test_execute_script():
|
||||
"""测试执行SQL脚本功能"""
|
||||
# 创建临时数据库文件
|
||||
with tempfile.NamedTemporaryFile(suffix='.db', delete=False) as tmp_file:
|
||||
with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as tmp_file:
|
||||
db_path = tmp_file.name
|
||||
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user