Skip to content

feat(tests): 完善项目测试#5272

Open
whatevertogo wants to merge 34 commits intoAstrBotDevs:masterfrom
whatevertogo:feat/add-comprehensive-tests
Open

feat(tests): 完善项目测试#5272
whatevertogo wants to merge 34 commits intoAstrBotDevs:masterfrom
whatevertogo:feat/add-comprehensive-tests

Conversation

@whatevertogo
Copy link
Contributor

@whatevertogo whatevertogo commented Feb 20, 2026

Motivation / 动机

This PR strengthens AstrBot’s testing infrastructure, significantly expands core-module coverage, and resolves a pipeline circular import issue discovered during test hardening.

该 PR 主要完善测试基础设施、显著提升核心模块测试覆盖率,并修复在补测过程中暴露的 pipeline 循环依赖问题。


Modifications / 改动点

1️⃣ Test Infrastructure / 测试基础设施

  • Centralized pytest configuration in pyproject.toml
    • markers
    • asyncio mode
    • logging
    • warning filters
    • test collection rules
  • Added shared global fixtures in tests/conftest.py
  • Added integration-specific fixtures in tests/integration/conftest.py
  • Introduced structured test layout:
    • tests/unit/
    • tests/integration/
    • tests/agent/
    • tests/fixtures/**
  • Extended Makefile test targets:
    • make test
    • make test-unit
    • make test-integration
    • make test-cov
    • make test-quick

Goal:

  • Standardize test execution
  • Improve isolation and maintainability
  • Provide scalable test foundation

2️⃣ Core Test Coverage Expansion / 核心模块覆盖扩展

Added or expanded tests for:

  • astr_main_agent
  • computer
  • config
  • conversation_mgr
  • core_lifecycle
  • cron_manager
  • event_bus
  • persona_mgr
  • pipeline import-cycle
  • smoke path

Updated existing tests:

  • tests/test_dashboard.py
  • tests/test_kb_import.py
  • tests/test_main.py
  • tests/test_plugin_manager.py
  • tests/agent/test_*

Goals:

  • Strengthen core behavior validation
  • Cover lifecycle and event flow
  • Surface structural issues early (e.g., circular imports)

3️⃣ Pipeline Import-Cycle Fix / Pipeline 循环依赖修复

During coverage expansion, an implicit circular import in the pipeline module was discovered and resolved.

Changes:

  • Refactored astrbot/core/pipeline/__init__.py to use lazy exports
  • Added:
    • bootstrap.py
    • stage_order.py
  • Updated scheduler bootstrap flow in scheduler.py
  • Fixed Stage import paths in:
    • agent_sub_stages/internal.py
    • agent_sub_stages/third_party.py

Impact:

  • No public API changes
  • No behavior changes
  • Structural dependency fix only
  • pyproject.toml 新增了 pytest, pytest-asyncio, pytest-mock 等依赖

Breaking Changes

  • This is NOT a breaking change.
  • 这不是一个破坏性变更。

Verification / 验证步骤

uv run pytest tests/test_smoke.py \
    tests/unit/test_import_cycles.py \
    tests/unit/test_core_lifecycle.py \
    tests/unit/test_conversation_mgr.py \
    tests/unit/test_config.py \
    tests/unit/test_astr_main_agent.py \
    tests/unit/test_computer.py -q
# 178 passed

uv run pytest tests/test_kb_import.py \
    tests/test_dashboard.py \
    tests/test_main.py -q
# 15 passed, 1 skipped

uv run ruff format .
# formatted / unchanged

uv run ruff check .
# All checks passed

Checklist / 检查清单

  • 😊 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。/ If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
  • 👀 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。/ My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
  • 🤓 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到了 requirements.txtpyproject.toml 文件相应位置。/ I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in requirements.txt and pyproject.toml.
  • 😮 我的更改没有引入恶意代码。/ My changes do not introduce malicious code.

审查总结

本 PR 主要围绕测试基础设施完善、核心模块测试覆盖扩展,以及一个 pipeline 循环依赖问题的修复展开。整体属于工程质量改进型变更,不涉及功能新增。


一、测试基础设施调整

本次变更对测试体系进行了结构化整理,包括:

  • pyproject.toml 中集中配置 pytest 相关选项(markers、asyncio、日志、收集规则等)
  • 引入全局与集成级 conftest.py,统一 fixture 管理
  • 规范 tests/ 目录结构(unit / integration / agent / fixtures)
  • 扩展 Makefile 中的测试命令入口

这些修改的主要作用是统一测试运行方式,提高测试隔离性与可维护性。


二、核心模块测试覆盖扩展

新增或强化了多个核心模块的测试,包括:

  • 生命周期管理
  • 配置管理
  • 会话管理
  • Agent 相关逻辑
  • 事件系统
  • 定时任务
  • Persona 管理
  • Pipeline 结构
  • 冒烟路径

测试扩展过程中发现并暴露了 pipeline 模块中的循环依赖问题,说明测试补充对结构性问题具有一定发现能力。


三、Pipeline 循环依赖修复

针对发现的循环导入问题,进行了内部结构调整:

  • 修改 __init__ 导出方式为延迟导出
  • 拆分 bootstrap 与 stage_order 相关逻辑
  • 调整部分内部 import 路径

该修复未改变对外接口,也未影响现有功能逻辑,属于内部结构层面的修正。


四、风险评估

  • 未引入新依赖
  • 未修改公共 API
  • 主要变更集中在测试与内部结构
  • 相关测试与静态检查已通过

整体风险较低。


总体结论

该 PR 主要提升测试结构与覆盖率,并修复一个内部循环依赖问题。
变更范围清晰,未涉及功能变更或接口调整,风险可控。

whatevertogo and others added 4 commits February 21, 2026 01:00
…ration tests

- Add `conftest.py` with 16 shared pytest fixtures for mock providers,
  platforms, events, contexts, and database instances
- Create structured test data in `tests/fixtures/` including configs,
  messages, and a sample plugin for consistent test inputs
- Implement integration test infrastructure in `tests/integration/`
  with specialized fixtures for multi-component testing
- Add unit test directory structure in `tests/unit/`
- Fix circular import in `astrbot/core/star/register/star.py`
- Update existing tests for compatibility with new fixtures:
  - `test_dashboard.py`: Fix async fixture scope issues
  - `test_plugin_manager.py`: Use new Context fixture with cron_manager
  - `test_kb_import.py`: Align with async fixture patterns
  - `test_main.py`: Improve mock handling
- Add `TEST_REQUIREMENTS.md` documenting ~415 test cases to implement
- Add pytest configuration to `pyproject.toml` with markers and settings
- Update `Makefile` with test commands (test, test-unit, test-cov, etc.)

Test coverage baseline: 34% (203 tests passing)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings February 20, 2026 17:19
@dosubot dosubot bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Feb 20, 2026
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @whatevertogo, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

此拉取请求旨在通过引入一个全面的测试框架来显著提升 AstrBot 项目的测试能力和代码质量。它不仅建立了统一的测试基础设施和清晰的测试目录结构,还重构了现有测试以适应新标准,并修复了一个关键的循环导入问题。这些改进将使开发人员能够更高效地编写、运行和维护测试,从而提高项目的稳定性和可维护性,并为未来的功能开发提供坚实的基础。

Highlights

  • 完整的测试框架搭建: 为 AstrBot 项目搭建了完整的测试框架,包括统一的测试基础设施、目录结构和运行命令,为后续测试用例的添加奠定了基础。
  • 现有测试重构与对齐: 重构了现有的测试文件,修复了异步 fixture 作用域问题,更新了 Context fixture 参数,并改进了 mock 处理,使其与新框架对齐。
  • 新增 Pytest 配置与 Makefile 命令: 在 pyproject.toml 中添加了详细的 Pytest 配置,包括测试路径、标记、异步设置和日志配置。同时,在 Makefile 中新增了 testtest-unittest-integrationtest-covtest-quick 等测试命令,简化了测试执行流程。
  • 循环导入问题修复: 修复了 astrbot/core/star/register/star.py 中的一个循环导入问题,提高了代码的健壮性。
  • 新增测试需求清单与 Claude Code 指南: 添加了详细的 TEST_REQUIREMENTS.md 文档,列出了约 415 个待实现的测试需求。同时,新增了 CLAUDE.md 文件,为 Claude Code 提供了项目概览、开发设置、架构和测试指南。
Changelog
  • CLAUDE.md
    • 新增了为 Claude Code 提供项目概览、开发设置、代码质量、架构、路径约定、测试、分支命名、提交信息格式和额外指南的文档。
  • Makefile
    • 更新了 .PHONY 声明,新增了 testtest-unittest-integrationtest-covtest-quick 等测试命令。
  • astrbot/core/star/register/star.py
    • 修复了循环导入问题,将 from astrbot.core.star import StarMetadata, star_map 修改为 from astrbot.core.star.star import StarMetadata, star_map
  • pyproject.toml
    • 新增了 [tool.pytest.ini_options] 配置,定义了 Pytest 的文件、类、函数识别规则、测试路径、不递归目录、附加选项、异步模式、fixture 作用域、自定义标记、最低版本、日志设置和警告过滤。
    • 扩展了 tool.pyright.exclude 列表,增加了 **/__pycache__**/.*.venv 等排除项。
  • tests/TEST_REQUIREMENTS.md
    • 新增了详细的测试需求清单文档,包括测试架构、运行测试命令、测试标记、可用 Fixtures、测试数据、模块测试需求(P0-P3 优先级)、现有测试分析、测试编写建议和进度追踪。
  • tests/init.py
    • 新增了测试包的 __init__.py 文件,包含包的 docstring 和 __all__ 导出列表。
  • tests/agent/test_context_manager.py
    • 更新了 test_compression_threshold_default 测试中的断言,以更准确地验证压缩阈值的默认行为。
  • tests/agent/test_truncator.py
    • 更新了 create_message 方法中 role 参数的类型提示,使用了 typing.Literal
  • tests/conftest.py
    • 新增了共享的 Pytest 配置和 Fixtures 文件,包括测试收集和排序逻辑、自定义标记注册、临时目录和文件 Fixtures、模拟对象 Fixtures(Provider、Platform、Conversation、Event)、配置 Fixtures、数据库 Fixtures、上下文 Fixtures 以及创建模拟 LLM 响应和消息组件的工具函数。
  • tests/fixtures/init.py
    • 新增了测试数据加载工具文件,提供了 load_fixtureget_fixture_path 函数用于加载 JSON 格式的测试数据和获取文件路径。
  • tests/fixtures/configs/test_cmd_config.json
    • 新增了测试用的命令配置文件。
  • tests/fixtures/messages/test_messages.json
    • 新增了包含多种模拟消息组件(纯文本、图片、@、回复、文件、组合消息)的测试数据文件。
  • tests/fixtures/plugins/fixture_plugin.py
    • 新增了最小化的测试插件文件,包含 TestPlugin 类及其初始化、终止方法,以及 test_commandtest_llm_tooltest_regex_handler 处理器。
  • tests/fixtures/plugins/metadata.yaml
    • 新增了测试插件的元数据文件。
  • tests/integration/init.py
    • 新增了集成测试包的 __init__.py 文件,包含包的 docstring。
  • tests/integration/conftest.py
    • 新增了集成测试专用的 Fixtures 文件,包括 integration_contextmock_llm_provider_for_integrationmock_platform_for_integrationmock_pipeline_contextpopulated_test_db
  • tests/integration/test_smoke_integration.py
    • 新增了集成测试的冒烟测试,验证 integration_context 的初始化。
  • tests/test_dashboard.py
    • 移除了 core_lifecycle_tdappauthenticated_header Fixtures 的 scope="module" 属性,使其作用域变为 function
    • 更新了 test_plugins 测试,使用 monkeypatch 模拟 plugin_managerinstall_pluginupdate_pluginuninstall_plugin 方法,不再直接检查 star_registrystar_handlers_registry
  • tests/test_kb_import.py
    • 移除了 core_lifecycle_tdappauthenticated_header Fixtures 的 scope="module" 属性,使其作用域变为 function
    • 更新了 core_lifecycle_td Fixture 中 kb_helper 的模拟方式,将其从 AsyncMock(spec=KBHelper) 更改为 MagicMock,并将其 upload_document 方法设置为 AsyncMock
    • 更新了 test_import_documents 测试中对 kb_helper.upload_document 调用次数和参数的验证,以适应新的模拟方式。
  • tests/test_main.py
    • 新增了 collections.namedtuple 导入,并创建了 _make_version_info 辅助函数来模拟 sys.version_info
    • 改进了 test_check_env 测试中的 monkeypatch 使用,使其在设置 sys.version_info 时不引发错误,并更全面地模拟了 main 模块中的路径获取函数。
    • 更新了 os.makedirs 的断言,以验证所有预期路径的创建。
  • tests/test_plugin_manager.py
    • 重构了 plugin_manager_pm Fixture,使其具有更好的隔离性,包括设置 ASTRBOT_ROOT 环境变量和调整 sys.path
    • 新增了 _write_local_test_plugin 辅助函数,用于在临时目录中创建本地测试插件文件。
    • 新增了 local_updator Fixture,用于模拟插件更新器的 installupdate 方法,以便在不进行网络请求的情况下测试插件安装和更新。
    • 更新了 test_install_plugintest_install_nonexistent_plugintest_update_plugintest_update_nonexistent_plugintest_uninstall_plugin 测试,使其使用新的 Fixtures 和模拟逻辑,并使用 TEST_PLUGIN_NAME 进行断言。
  • tests/test_quoted_message_parser.py
    • 新增了 pyright 注释 # pyright: reportArgumentType=false, reportOperatorIssue=false 以抑制特定的类型检查警告。
  • tests/unit/init.py
    • 新增了单元测试包的 __init__.py 文件,包含包的 docstring。
  • tests/unit/test_fixture_plugin_usage.py
    • 新增了测试文件,验证 fixture_plugin.pymetadata.yaml 文件是否存在,并测试 fixture_plugin.py 可以在隔离进程中成功导入和检查其内容。
Activity
  • whatevertogo 创建了此拉取请求,旨在为 AstrBot 项目搭建完整的测试框架并重构现有测试。
  • 拉取请求描述中详细列出了动机、改动点(测试框架基础设施、目录结构、现有测试重构、其他改动、Bug 修复),并提供了测试结果和命令示例。
  • 描述中还包含了检查清单,表明作者已验证更改经过良好测试,并提供了验证步骤和运行截图。
  • 此拉取请求由 Claude Code 生成。
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@dosubot
Copy link

dosubot bot commented Feb 20, 2026

Related Documentation

Checked 1 published document(s) in 1 knowledge base(s). No updates required.

How did I do? Any feedback?  Join Discord

@dosubot dosubot bot added the area:core The bug / feature is about astrbot's core, backend label Feb 20, 2026
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了 3 个问题,并提供了一些整体反馈:

  • 在 tests/init.py 中,你通过 __all__ 暴露了 create_mock_llm_responsecreate_mock_message_component,但这些符号只在 tests/conftest.py 中定义且从未被导入,因此 from tests import create_mock_llm_response 会失败;请要么在 tests/init.py 中导入它们,要么将它们从 __all__ 中移除。
  • 测试 test_fixture_plugin_can_be_imported_in_isolated_process 每次运行都会启动一个子进程,这相对较慢,而且在失败时更难调试;除非确实需要验证进程级隔离,否则建议重构为纯 Python 的导入测试(例如在同一进程中使用 importlib)。
  • 全局 conftest 和集成测试的 conftest 都修改了 sys.path 和环境变量;为了降低未来测试中出现意外交互的风险,最好将这类设置集中到一个地方(例如单一的 conftest),或者更严格地限定这些修改的作用范围。
给 AI Agents 的提示
Please address the comments from this code review:

## Overall Comments
- In tests/__init__.py you expose `create_mock_llm_response` and `create_mock_message_component` via `__all__`, but these symbols are only defined in tests/conftest.py and never imported, so `from tests import create_mock_llm_response` will fail; either import them into tests/__init__.py or drop them from `__all__`.
- The test `test_fixture_plugin_can_be_imported_in_isolated_process` spawns a subprocess on every run, which can be relatively slow and harder to debug when it fails; consider refactoring to a pure-Python import test (e.g., using importlib within the same process) unless there is a strong need to validate process-level isolation.
- Both the global conftest and integration conftest mutate sys.path and environment variables; it might be safer to centralize this setup (e.g., in a single conftest) or to scope the mutations more narrowly to reduce the risk of surprising interactions in future tests.

## Individual Comments

### Comment 1
<location> `tests/test_plugin_manager.py:64-65` </location>
<code_context>
+    (data_dir / "__init__.py").write_text("", encoding="utf-8")
+    (plugin_dir / "__init__.py").write_text("", encoding="utf-8")
+
+    monkeypatch.setenv("ASTRBOT_ROOT", str(test_root))
+    if str(test_root) not in sys.path:
+        sys.path.insert(0, str(test_root))

</code_context>

<issue_to_address>
**suggestion (testing):** Avoid leaking `sys.path` / environment changes from `plugin_manager_pm` fixture across tests

This fixture mutates global state (`ASTRBOT_ROOT`, `sys.path`) without restoring it, which can make tests order-dependent or flaky, especially under parallel runs. Please either use `monkeypatch` for `sys.path` as well, or switch to a `yield`-style fixture that captures and restores `sys.path` (and any env changes) to keep tests isolated.
</issue_to_address>

### Comment 2
<location> `tests/unit/test_fixture_plugin_usage.py:16-25` </location>
<code_context>
+    assert metadata_file.exists()
+
+
+def test_fixture_plugin_can_be_imported_in_isolated_process():
+    plugin_file = get_fixture_path("plugins/fixture_plugin.py")
+    repo_root = Path(__file__).resolve().parents[2]
+
+    script = "\n".join(
+        [
+            "import importlib.util",
+            f'plugin_file = r"{plugin_file}"',
+            "spec = importlib.util.spec_from_file_location('fixture_test_plugin', plugin_file)",
+            "assert spec is not None",
+            "assert spec.loader is not None",
+            "module = importlib.util.module_from_spec(spec)",
+            "spec.loader.exec_module(module)",
+            "plugin_cls = getattr(module, 'TestPlugin', None)",
+            "assert plugin_cls is not None",
+            "assert hasattr(plugin_cls, 'test_command')",
+            "assert hasattr(plugin_cls, 'test_llm_tool')",
+            "assert hasattr(plugin_cls, 'test_regex_handler')",
+        ],
+    )
+
+    result = subprocess.run(
</code_context>

<issue_to_address>
**suggestion (testing):** Consider marking the subprocess-based fixture plugin test as `@pytest.mark.slow`

This test starts a real Python subprocess, which is slower than in-process tests. Since a `slow` marker already exists in `tests/conftest.py`, please add `@pytest.mark.slow` so it can be skipped in quick runs (e.g. `-m "not slow"`) while still running in full test suites.

Suggested implementation:

```python
import pytest


def test_fixture_plugin_files_exist():

```

```python
@pytest.mark.slow
def test_fixture_plugin_can_be_imported_in_isolated_process():

```

If `pytest` is already imported elsewhere in this file, you should remove the duplicate `import pytest` introduced by the first change block to avoid redundant imports.
</issue_to_address>

### Comment 3
<location> `tests/__init__.py:16-18` </location>
<code_context>
+  └── test_*.py           # 根级别测试文件
+"""
+
+__all__ = [
+    "create_mock_llm_response",
+    "create_mock_message_component",
+]
</code_context>

<issue_to_address>
**issue (bug_risk):** `__all__` exports helpers that are not defined in this module

These names are only defined in `tests/conftest.py` and aren’t imported into `tests/__init__`, so they’re not actually available as `tests.create_mock_llm_response` / `tests.create_mock_message_component`. Either import them here (e.g. `from .conftest import create_mock_llm_response, create_mock_message_component`) or update `__all__` to only list symbols that this module really exports, to avoid import failures and a misleading package API.
</issue_to_address>

Sourcery 对开源项目免费使用——如果你觉得这次评审有帮助,欢迎分享给更多人 ✨
帮我变得更有用!请对每条评论点击 👍 或 👎,我会根据你的反馈改进之后的评审。
Original comment in English

Hey - I've found 3 issues, and left some high level feedback:

  • In tests/init.py you expose create_mock_llm_response and create_mock_message_component via __all__, but these symbols are only defined in tests/conftest.py and never imported, so from tests import create_mock_llm_response will fail; either import them into tests/init.py or drop them from __all__.
  • The test test_fixture_plugin_can_be_imported_in_isolated_process spawns a subprocess on every run, which can be relatively slow and harder to debug when it fails; consider refactoring to a pure-Python import test (e.g., using importlib within the same process) unless there is a strong need to validate process-level isolation.
  • Both the global conftest and integration conftest mutate sys.path and environment variables; it might be safer to centralize this setup (e.g., in a single conftest) or to scope the mutations more narrowly to reduce the risk of surprising interactions in future tests.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In tests/__init__.py you expose `create_mock_llm_response` and `create_mock_message_component` via `__all__`, but these symbols are only defined in tests/conftest.py and never imported, so `from tests import create_mock_llm_response` will fail; either import them into tests/__init__.py or drop them from `__all__`.
- The test `test_fixture_plugin_can_be_imported_in_isolated_process` spawns a subprocess on every run, which can be relatively slow and harder to debug when it fails; consider refactoring to a pure-Python import test (e.g., using importlib within the same process) unless there is a strong need to validate process-level isolation.
- Both the global conftest and integration conftest mutate sys.path and environment variables; it might be safer to centralize this setup (e.g., in a single conftest) or to scope the mutations more narrowly to reduce the risk of surprising interactions in future tests.

## Individual Comments

### Comment 1
<location> `tests/test_plugin_manager.py:64-65` </location>
<code_context>
+    (data_dir / "__init__.py").write_text("", encoding="utf-8")
+    (plugin_dir / "__init__.py").write_text("", encoding="utf-8")
+
+    monkeypatch.setenv("ASTRBOT_ROOT", str(test_root))
+    if str(test_root) not in sys.path:
+        sys.path.insert(0, str(test_root))

</code_context>

<issue_to_address>
**suggestion (testing):** Avoid leaking `sys.path` / environment changes from `plugin_manager_pm` fixture across tests

This fixture mutates global state (`ASTRBOT_ROOT`, `sys.path`) without restoring it, which can make tests order-dependent or flaky, especially under parallel runs. Please either use `monkeypatch` for `sys.path` as well, or switch to a `yield`-style fixture that captures and restores `sys.path` (and any env changes) to keep tests isolated.
</issue_to_address>

### Comment 2
<location> `tests/unit/test_fixture_plugin_usage.py:16-25` </location>
<code_context>
+    assert metadata_file.exists()
+
+
+def test_fixture_plugin_can_be_imported_in_isolated_process():
+    plugin_file = get_fixture_path("plugins/fixture_plugin.py")
+    repo_root = Path(__file__).resolve().parents[2]
+
+    script = "\n".join(
+        [
+            "import importlib.util",
+            f'plugin_file = r"{plugin_file}"',
+            "spec = importlib.util.spec_from_file_location('fixture_test_plugin', plugin_file)",
+            "assert spec is not None",
+            "assert spec.loader is not None",
+            "module = importlib.util.module_from_spec(spec)",
+            "spec.loader.exec_module(module)",
+            "plugin_cls = getattr(module, 'TestPlugin', None)",
+            "assert plugin_cls is not None",
+            "assert hasattr(plugin_cls, 'test_command')",
+            "assert hasattr(plugin_cls, 'test_llm_tool')",
+            "assert hasattr(plugin_cls, 'test_regex_handler')",
+        ],
+    )
+
+    result = subprocess.run(
</code_context>

<issue_to_address>
**suggestion (testing):** Consider marking the subprocess-based fixture plugin test as `@pytest.mark.slow`

This test starts a real Python subprocess, which is slower than in-process tests. Since a `slow` marker already exists in `tests/conftest.py`, please add `@pytest.mark.slow` so it can be skipped in quick runs (e.g. `-m "not slow"`) while still running in full test suites.

Suggested implementation:

```python
import pytest


def test_fixture_plugin_files_exist():

```

```python
@pytest.mark.slow
def test_fixture_plugin_can_be_imported_in_isolated_process():

```

If `pytest` is already imported elsewhere in this file, you should remove the duplicate `import pytest` introduced by the first change block to avoid redundant imports.
</issue_to_address>

### Comment 3
<location> `tests/__init__.py:16-18` </location>
<code_context>
+  └── test_*.py           # 根级别测试文件
+"""
+
+__all__ = [
+    "create_mock_llm_response",
+    "create_mock_message_component",
+]
</code_context>

<issue_to_address>
**issue (bug_risk):** `__all__` exports helpers that are not defined in this module

These names are only defined in `tests/conftest.py` and aren’t imported into `tests/__init__`, so they’re not actually available as `tests.create_mock_llm_response` / `tests.create_mock_message_component`. Either import them here (e.g. `from .conftest import create_mock_llm_response, create_mock_message_component`) or update `__all__` to only list symbols that this module really exports, to avoid import failures and a misleading package API.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

这次的 PR 对项目的质量和可维护性是巨大的一步。它引入了一个全面的、基于 pytest 的测试框架,包含了结构良好的 fixtures 和测试组织。重构现有测试以消除网络依赖并提高隔离性是一个显著的进步。TEST_REQUIREMENTS.md 的添加为未来的测试开发提供了清晰的路线图。循环导入的修复也已注意到。我有几个关于文档一致性和测试代码质量的建议。

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR establishes a comprehensive test framework infrastructure for the AstrBot project, which is a multi-platform LLM chatbot written in Python. The PR refactors existing tests to use the new framework and documents approximately 415 future test requirements.

Changes:

  • Adds test infrastructure with 16 shared pytest fixtures for mocking providers, platforms, databases, and contexts
  • Creates structured test directories (tests/unit/, tests/integration/, tests/fixtures/) with proper configuration
  • Refactors 7 existing test files to use new fixtures and fixes async fixture scope issues
  • Fixes a circular import bug in astrbot/core/star/register/star.py

Reviewed changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
tests/conftest.py Adds 16 shared fixtures, pytest configuration hooks, and utility functions
tests/integration/conftest.py Adds integration-specific fixtures for full context, LLM providers, and platforms
tests/init.py, tests/unit/init.py, tests/integration/init.py Package initialization with documentation
tests/fixtures/init.py Helper functions for loading test data (load_fixture, get_fixture_path)
tests/fixtures/plugins/*.py, *.yaml Test plugin files for plugin system validation
tests/fixtures/messages/test_messages.json Test message data fixtures
tests/fixtures/configs/test_cmd_config.json Test configuration data
tests/test_plugin_manager.py Refactored to use local mocks instead of external network calls
tests/test_dashboard.py Fixed async fixture scopes from module to function
tests/test_kb_import.py Aligned async fixture patterns
tests/test_main.py Improved mock handling with namedtuple for version_info
tests/agent/test_truncator.py Added explicit type hints for role parameter
tests/agent/test_context_manager.py Adjusted compression threshold test
tests/test_quoted_message_parser.py Added pyright directive to suppress type warnings
tests/unit/test_fixture_plugin_usage.py New test validating fixture plugin can be imported
tests/integration/test_smoke_integration.py New smoke test for integration context bootstrap
pyproject.toml Added comprehensive pytest configuration including markers, asyncio settings, and warnings
Makefile Added test commands (test, test-unit, test-integration, test-cov, test-quick)
tests/TEST_REQUIREMENTS.md Comprehensive documentation of 415 test requirements across all modules
CLAUDE.md Development guidance for Claude Code
astrbot/core/star/register/star.py Fixed circular import by using explicit import path

whatevertogo and others added 3 commits February 21, 2026 01:28
- Fix `tests/__init__.py`: Remove misleading `__all__` exports that
  reference functions defined in conftest.py
- Fix `tests/test_plugin_manager.py`: Use `monkeypatch.syspath_prepend()`
  instead of manual sys.path manipulation to ensure proper cleanup

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use `pytest_asyncio.fixture` for async fixtures to ensure proper
  event loop handling (temp_db, mock_context, plugin_manager_pm)
- Fix `plugin_manager_pm` fixture to properly cleanup database with
  yield/finally pattern
- Add missing `ignore_version_check` parameter to mock_install_plugin
- Remove unnecessary pyright ignore comments from test_quoted_message_parser.py
- Improve error handling in test_fixture_plugin_usage.py
- Update CLAUDE.md with correct test command
- Fix docstring reference from pytest.ini to pyproject.toml

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@chatgpt-codex-connector
Copy link

To use Codex here, create a Codex account and connect to github.

@whatevertogo
Copy link
Contributor Author

@codex

@chatgpt-codex-connector
Copy link

To use Codex here, create a Codex account and connect to github.

3 similar comments
@chatgpt-codex-connector
Copy link

To use Codex here, create a Codex account and connect to github.

@chatgpt-codex-connector
Copy link

To use Codex here, create a Codex account and connect to github.

@chatgpt-codex-connector
Copy link

To use Codex here, create a Codex account and connect to github.

@whatevertogo
Copy link
Contributor Author

@codex 干活

@chatgpt-codex-connector
Copy link

To use Codex here, create a Codex account and connect to github.

@whatevertogo
Copy link
Contributor Author

@codex 干活

@chatgpt-codex-connector
Copy link

To use Codex here, create a Codex account and connect to github.

@zouyonghe
Copy link
Member

@sourcery-ai review

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了 1 个问题,并给出了一些总体反馈:

  • conftest 模块通过修改 sys.path 来导入项目(在 tests/conftest.py 和 tests/integration/conftest.py 中都是如此);建议改为依赖可编辑安装(editable install)或设置 PYTHONPATH,这样测试环境与真实场景下的导入行为更一致,也能避免一些隐蔽的路径问题。
  • 环境变量 TESTING 和 ASTRBOT_TEST_MODE 在多个 conftest 中被设置;建议将其集中到一个地方(例如顶层的 conftest 或测试运行脚本)里统一配置,以减少重复并降低测试环境不一致的风险。
给 AI Agent 的提示
Please address the comments from this code review:

## Overall Comments
- The conftest modules manipulate sys.path to import the project (both in tests/conftest.py and tests/integration/conftest.py); consider relying on an editable install or PYTHONPATH instead so tests more closely match real-world import behavior and avoid subtle path bugs.
- Environment variables TESTING and ASTRBOT_TEST_MODE are set in multiple conftests; centralizing this in a single place (e.g., top-level conftest or test runner script) would reduce duplication and the risk of inconsistent test environments.

## Individual Comments

### Comment 1
<location> `pyproject.toml:117-120` </location>
<code_context>
+log_file_level = "DEBUG"
+log_file_format = "%(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)"
+log_file_date_format = "%Y-%m-%d %H:%M:%S"
+filterwarnings = [
+  "ignore::DeprecationWarning",
+  "ignore::PendingDeprecationWarning",
+  "ignore:.*unclosed.*:ResourceWarning",
+]
+
</code_context>

<issue_to_address>
**suggestion (bug_risk):** 忽略所有关于未关闭资源的 `ResourceWarning` 消息,可能会掩盖真实的资源泄漏问题。

这个宽泛的 `ignore:.*unclosed.*:ResourceWarning` 过滤规则会关闭对真实泄漏(文件、套接字等)的检测。请将它限定在已知噪声较多的调用点/模块上,或者调整警告过滤器(例如使用 `default`/`once`),以便新的泄漏仍然能暴露出来。

建议实现方式:

```
  "default:.*unclosed.*:ResourceWarning",

```

1. 确保整个 `filterwarnings = [...]` 块定义在 `[tool.pytest.ini_options]` 段内,以便 pytest 能正确应用。
2. 如果你知道某些特定的第三方模块会产生无害但噪声很大的未关闭资源警告,可以进一步收窄该规则只针对这些模块,例如:
   - `"ignore:.*unclosed.*:ResourceWarning:urllib3.connectionpool"`
   同时对其他情况保留通用的 `default:.*unclosed.*:ResourceWarning`。
</issue_to_address>

Sourcery 对开源项目是免费的——如果你觉得我们的代码评审有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续的评审。
Original comment in English

Hey - I've found 1 issue, and left some high level feedback:

  • The conftest modules manipulate sys.path to import the project (both in tests/conftest.py and tests/integration/conftest.py); consider relying on an editable install or PYTHONPATH instead so tests more closely match real-world import behavior and avoid subtle path bugs.
  • Environment variables TESTING and ASTRBOT_TEST_MODE are set in multiple conftests; centralizing this in a single place (e.g., top-level conftest or test runner script) would reduce duplication and the risk of inconsistent test environments.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The conftest modules manipulate sys.path to import the project (both in tests/conftest.py and tests/integration/conftest.py); consider relying on an editable install or PYTHONPATH instead so tests more closely match real-world import behavior and avoid subtle path bugs.
- Environment variables TESTING and ASTRBOT_TEST_MODE are set in multiple conftests; centralizing this in a single place (e.g., top-level conftest or test runner script) would reduce duplication and the risk of inconsistent test environments.

## Individual Comments

### Comment 1
<location> `pyproject.toml:117-120` </location>
<code_context>
+log_file_level = "DEBUG"
+log_file_format = "%(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)"
+log_file_date_format = "%Y-%m-%d %H:%M:%S"
+filterwarnings = [
+  "ignore::DeprecationWarning",
+  "ignore::PendingDeprecationWarning",
+  "ignore:.*unclosed.*:ResourceWarning",
+]
+
</code_context>

<issue_to_address>
**suggestion (bug_risk):** Ignoring all `ResourceWarning` messages about unclosed resources can hide real resource-leak issues.

This broad `ignore:.*unclosed.*:ResourceWarning` suppression turns off detection of real leaks (files, sockets, etc.). Please scope it to known noisy call sites/modules, or adjust the warnings filter (e.g., `default`/`once`) so new leaks still surface.

Suggested implementation:

```
  "default:.*unclosed.*:ResourceWarning",

```

1. Ensure the entire `filterwarnings = [...]` block is defined inside the `[tool.pytest.ini_options]` section so pytest applies it.
2. If you know specific noisy third‑party modules that generate benign unclosed‑resource warnings, you can further refine this rule to target them, e.g.:
   - `"ignore:.*unclosed.*:ResourceWarning:urllib3.connectionpool"`
   while keeping the general `default:.*unclosed.*:ResourceWarning` for everything else.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@zouyonghe
Copy link
Member

建议把功能型问题多review一下,工程型建议只做参考

@whatevertogo whatevertogo marked this pull request as ready for review February 22, 2026 13:22
@auto-assign auto-assign bot requested review from Raven95676 and anka-afk February 22, 2026 13:22
@dosubot dosubot bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:XXL This PR changes 1000+ lines, ignoring generated files. labels Feb 22, 2026
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @whatevertogo, your pull request is larger than the review limit of 150000 diff characters

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 73 out of 73 changed files in this pull request and generated no new comments.

@whatevertogo whatevertogo marked this pull request as draft February 22, 2026 13:50
@whatevertogo whatevertogo marked this pull request as ready for review February 22, 2026 15:01
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @whatevertogo, your pull request is larger than the review limit of 150000 diff characters

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 74 out of 74 changed files in this pull request and generated no new comments.

@whatevertogo
Copy link
Contributor Author

702fdd00-7275-419e-8141-4fc1311c01ea

@whatevertogo
Copy link
Contributor Author

测试应该是隔离的没问题,注意一下解决循环依赖改的一些代码就行了,我个人没看出来有问题

@whatevertogo
Copy link
Contributor Author

我把改动拆分成了多个小 PR,方便大家审阅。这个 PR 目前用来代表主测试分支的整体进度。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core The bug / feature is about astrbot's core, backend lgtm This PR has been approved by a maintainer size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants