Python 高级测试模式实战:pytest 异步测试、Monkeypatch、属性测试与数据库测试完整指南
2026/9/11 21:14:02 网站建设 项目流程

Python 高级测试模式实战:pytest 异步测试、Monkeypatch、属性测试与数据库测试完整指南

【免费下载链接】agentsMulti-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity项目地址: https://gitcode.com/GitHub_Trending/agents24/agents

本文是 agents 插件市场python-development技能包中 python-testing-patterns 技能 的进阶参考(advanced-patterns.md)系统化讲解,覆盖异步代码测试、monkeypatching、临时文件、conftest 共享夹具、基于 Hypothesis 的属性测试、数据库测试、CI/CD 集成与 pytest 配置文件六大主题。读完本文,你将掌握一套可直接落地到真实项目的 pytest 高级测试方案,并理解这些模式在本仓库plugin-eval评估框架测试套件中的实际落地方式。

一、文档定位:从基础到高级的三级知识导航

本仓库的python-testing-patterns技能采用"摘要 → 详情 → 进阶"三级文档结构组织测试知识:

层级文件内容定位
导航层SKILL.md技能元信息、适用场景、测试类型、AAA 模式、Quick Start、命名规范、marker 与覆盖率速览
基础层references/details.mdPattern 1–5:基础 pytest、fixture 设置/清理、参数化测试、unittest.mock、异常测试
进阶层references/advanced-patterns.mdPattern 6–10:异步、monkeypatch、临时文件、conftest、属性测试,外加数据库、CI/CD 与配置

本文聚焦进阶层。这些模式属于"进阶"而非"边缘":凡是涉及异步 I/O、外部环境变量、文件系统副作用、跨测试共享状态、数据不可穷举或数据库依赖的测试,都必然要动用这里的技术。在写作任何测试套件之前,建议先按 SKILL.md 中的 AAA(Arrange-Act-Assert)结构与"一个测试只验证一个行为"的原则搭好骨架,再用本文的进阶模式解决具体难题。

二、环境准备:进阶模式需要哪些依赖

进阶模式涉及的插件依赖如下:

  • pytest-asyncio:为@pytest.mark.asyncio与异步 fixture 提供运行时支持;
  • pytest-cov:覆盖率统计与报告;
  • hypothesis:属性测试策略库;
  • freezegun(SKILL.md 中有专节):时间冻结。

本仓库真实项目 plugin-eval 的dev可选依赖即为一个标准参考组合:

[project.optional-dependencies] dev = [ "pytest>=9.1.1", "pytest-asyncio>=1.4.0", "pytest-cov>=6.0", "ruff>=0.16.3", "ty>=0.0.71", ]

值得注意的实践细节是:该项目的[tool.pytest.ini_options]开启了asyncio_mode = "auto",这意味着异步测试函数无需显式打@pytest.mark.asyncio装饰器也能被自动识别运行。下面的示例为保持教学明确性仍显式使用装饰器,但你在自己的项目中完全可以依据asyncio_mode的配置风格选择写法。

三、Pattern 6:异步代码测试(Testing Async Code)

现代 Python 后端大量使用async/await,异步代码的测试难点在于:事件循环的管理、并发任务的正确性验证、以及异步 fixture 的清理时机。本模式给出三类标准解法。

3.1 基础异步测试与并发测试

# test_async.py import pytest import asyncio async def fetch_data(url: str) -> dict: """Fetch data asynchronously.""" await asyncio.sleep(0.1) return {"url": url, "data": "result"} @pytest.mark.asyncio async def test_fetch_data(): """Test async function.""" result = await fetch_data("https://api.example.com") assert result["url"] == "https://api.example.com" assert "data" in result @pytest.mark.asyncio async def test_concurrent_fetches(): """Test concurrent async operations.""" urls = ["url1", "url2", "url3"] tasks = [fetch_data(url) for url in urls] results = await asyncio.gather(*tasks) assert len(results) == 3 assert all("data" in r for r in results)

要点拆解:

  • @pytest.mark.asyncio让 pytest 在事件循环中运行测试函数,而非以普通同步函数方式调用;
  • 第二个测试使用asyncio.gather(*tasks)并发执行三个协程,验证的是"并发不丢结果、不串数据"这一并发正确性;
  • 断言len(results) == 3all("data" in r for r in results)同时覆盖了数量与内容两个维度,符合 details.md 中"一个测试验证一个行为"的思想(此处验证的单一行为即"并发抓取返回全部结果")。

3.2 异步 fixture

@pytest.fixture async def async_client(): """Async fixture.""" client = {"connected": True} yield client client["connected"] = False @pytest.mark.asyncio async def test_with_async_fixture(async_client): """Test using async fixture.""" assert async_client["connected"] is True

异步 fixture 与同步 fixture 在写法上几乎一致:yield之前是 setup,之后是 teardown。区别在于 pytest-asyncio 会在事件循环上下文里执行 fixture 的yield前后逻辑,因此可以在 teardown 阶段安全地执行需要await的关闭操作(例如关闭 aiohttp session、断开 websocket)。本例用client["connected"] = False模拟了"测试结束后连接被关闭"的清理语义。

四、Pattern 7:Monkeypatch 测试外部依赖

monkeypatch 是 pytest 内置的 fixture,用于在测试期间安全地"篡改"环境变量、对象属性与模块属性,并在测试结束后自动还原。它比unittest.mock.patch更贴近 pytest 风格,且无需手动管理with块。

4.1 环境变量:setenv / delenv

# test_environment.py import os import pytest def get_database_url() -> str: """Get database URL from environment.""" return os.environ.get("DATABASE_URL", "sqlite:///:memory:") def test_database_url_default(): """Test default database URL.""" # Will use actual environment variable if set url = get_database_url() assert url def test_database_url_custom(monkeypatch): """Test custom database URL with monkeypatch.""" monkeypatch.setenv("DATABASE_URL", "postgresql://localhost/test") assert get_database_url() == "postgresql://localhost/test" def test_database_url_not_set(monkeypatch): """Test when env var is not set.""" monkeypatch.delenv("DATABASE_URL", raising=False) assert get_database_url() == "sqlite:///:memory:"

三个测试合在一起,构成了对"读取环境变量、带回退默认值"这一逻辑的完整覆盖:

  • test_database_url_default走真实环境(若 CI 中设置了变量则断言依然成立,因为只断言url非空);
  • monkeypatch.setenv(...)模拟外部注入,验证自定义配置路径;
  • monkeypatch.delenv(..., raising=False)模拟"变量未设置"的场景,raising=False保证变量不存在时不会抛KeyError,从而验证回退到sqlite:///:memory:的默认分支。

这正是 details.md 中"测试错误路径,而不只测试快乐路径"原则的典型体现——默认分支就是最容易漏测的"隐性错误路径"。

4.2 对象属性:setattr

class Config: """Configuration class.""" def __init__(self): self.api_key = "production-key" def get_api_key(self): return self.api_key def test_monkeypatch_attribute(monkeypatch): """Test monkeypatching object attributes.""" config = Config() monkeypatch.setattr(config, "api_key", "test-key") assert config.get_api_key() == "test-key"

monkeypatch.setattr除了可以接收(对象, 属性名, 值),也支持(模块, 属性名, 值)形式来替换模块级函数或类。其核心价值是自动还原:无论测试成功还是失败,pytest 都会在测试结束后恢复被篡改的值,避免污染其他测试。这使 monkeypatch 成为测试"读取环境变量、读取配置、依赖全局状态"类代码的首选工具。

五、Pattern 8:临时文件与目录(tmp_path)

测试文件读写逻辑时,绝不能把测试数据写进项目目录或系统临时目录的固定位置——那样既污染环境,又会在并行运行时互相冲突。pytest 内置的tmp_pathfixture 为每个测试提供独立的临时目录(类型为pathlib.Path),测试结束自动清理。

# test_file_operations.py import pytest from pathlib import Path def save_data(filepath: Path, data: str): """Save data to file.""" filepath.write_text(data) def load_data(filepath: Path) -> str: """Load data from file.""" return filepath.read_text() def test_file_operations(tmp_path): """Test file operations with temporary directory.""" # tmp_path is a pathlib.Path object test_file = tmp_path / "test_data.txt" # Save data save_data(test_file, "Hello, World!") # Verify file exists assert test_file.exists() # Load and verify data data = load_data(test_file) assert data == "Hello, World!" def test_multiple_files(tmp_path): """Test with multiple temporary files.""" files = { "file1.txt": "Content 1", "file2.txt": "Content 2", "file3.txt": "Content 3" } for filename, content in files.items(): filepath = tmp_path / filename save_data(filepath, content) # Verify all files created assert len(list(tmp_path.iterdir())) == 3 # Verify contents for filename, expected_content in files.items(): filepath = tmp_path / filename assert load_data(filepath) == expected_content

关键细节:

  • tmp_path直接就是pathlib.Path,因此tmp_path / "test_data.txt"的路径拼接语法开箱即用,无需os.path.join
  • 每个测试函数拿到的是不同的临时目录,天然满足 SKILL.md 中"测试隔离(Test Isolation)"的要求——测试之间无共享文件状态;
  • 第二个测试演示了批量文件场景:先验证文件数量(len(list(tmp_path.iterdir())) == 3),再逐一验证内容,覆盖了"数量 + 内容"两层断言;
  • 如需在会话级共享临时目录(例如超大文件或昂贵的 fixture 数据),pytest 还提供tmp_path_factory,但默认tmp_path的"每测试独立"语义已能满足绝大多数单元测试需求。

六、Pattern 9:自定义 Fixture 与 conftest 共享

conftest.py是 pytest 的"共享夹具仓库":放在某个目录下的conftest.py,其中的 fixture 对该目录及其所有子目录下的测试自动可见,无需显式导入。这是大型测试套件组织共享状态的标准手段,与本仓库 plugin-eval 的真实实践完全一致。

6.1 共享 fixture、autouse 与参数化 fixture

# conftest.py """Shared fixtures for all tests.""" import pytest @pytest.fixture(scope="session") def database_url(): """Provide database URL for all tests.""" return "postgresql://localhost/test_db" @pytest.fixture(autouse=True) def reset_database(database_url): """Auto-use fixture that runs before each test.""" # Setup: Clear database print(f"Clearing database: {database_url}") yield # Teardown: Clean up print("Test completed") @pytest.fixture def sample_user(): """Provide sample user data.""" return { "id": 1, "name": "Test User", "email": "test@example.com" } @pytest.fixture def sample_users(): """Provide list of sample users.""" return [ {"id": 1, "name": "User 1"}, {"id": 2, "name": "User 2"}, {"id": 3, "name": "User 3"}, ] # Parametrized fixture @pytest.fixture(params=["sqlite", "postgresql", "mysql"]) def db_backend(request): """Fixture that runs tests with different database backends.""" return request.param def test_with_db_backend(db_backend): """This test will run 3 times with different backends.""" print(f"Testing with {db_backend}") assert db_backend in ["sqlite", "postgresql", "mysql"]

逐项解读:

  • scope="session"database_url在整个测试会话中只创建一次,适合连接串、全局配置等"创建成本高、内容不变"的资源。scope还有function(默认,每测试一次)、moduleclasspackage等选项,details.md 的 Pattern 2 中给出了module级 fixture(如昂贵的 API 客户端)的示例,可按资源生命周期选择;
  • autouse=Truereset_database不需要测试函数声明参数也会自动在每个测试前后执行,适合"全局前置清理/后置收尾"类逻辑。这里用yield分隔 setup(清库)与 teardown(打印完成标记),与 Pattern 6 中异步 fixture 的yield语义一致;
  • params=[...]:参数化 fixture 会让每个使用它的测试分别以每个参数运行一次test_with_db_backend因此会被执行 3 次,分别验证 sqlite / postgresql / mysql 三种后端。这是"同一测试逻辑、多种运行环境"的标准做法,与@pytest.mark.parametrize形成互补:前者针对 fixture 层,后者针对测试函数入参。

6.2 仓库实战:plugin-eval 的 conftest 实践

本仓库 plugin-eval 正是 Pattern 8 与 Pattern 9 的活教材。其conftest.py顶层定义了一组基于tmp_path的组合 fixture:

@pytest.fixture def fixtures_dir() -> Path: return Path(__file__).parent / "fixtures" @pytest.fixture def sample_skill_dir(tmp_path: Path) -> Path: """Create a minimal valid skill directory.""" skill_dir = tmp_path / "test-skill" skill_dir.mkdir() skill_md = skill_dir / "SKILL.md" skill_md.write_text(...) refs_dir = skill_dir / "references" refs_dir.mkdir() (refs_dir / "guide.md").write_text("# Guide\n\nDetailed reference content.\n") return skill_dir @pytest.fixture def sample_plugin_dir(tmp_path: Path, sample_skill_dir: Path) -> Path: """Create a minimal valid plugin directory.""" plugin_dir = tmp_path / "test-plugin" plugin_dir.mkdir() ...

可以看到真实的 fixture 设计遵循了本文档的几条核心约定:

  1. fixture可以依赖其他 fixturesample_plugin_dir注入sample_skill_dir),形成组合复用;
  2. 使用tmp_path构建隔离的文件系统环境,测试互不干扰;
  3. 返回pathlib.Path而非字符串路径,方便后续mkdir()write_text()链式操作;
  4. fixture 放在conftest.py顶层,对全部测试文件共享(其 tests/test_cli.py 中的test_score_nonexistent_path也直接使用tmp_path构造不存在路径来验证 CLI 错误分支)。

七、Pattern 10:基于 Hypothesis 的属性测试

传统示例测试只能覆盖你"想得到"的输入;属性测试(property-based testing)则由 Hypothesis 自动生成大量随机输入,并验证代码的通用性质(property)。它对字符串处理、排序、数学运算、序列操作等"输入空间巨大"的代码尤其有效。

# test_properties.py from hypothesis import given, strategies as st import pytest def reverse_string(s: str) -> str: """Reverse a string.""" return s[::-1] @given(st.text()) def test_reverse_twice_is_original(s): """Property: reversing twice returns original.""" assert reverse_string(reverse_string(s)) == s @given(st.text()) def test_reverse_length(s): """Property: reversed string has same length.""" assert len(reverse_string(s)) == len(s) @given(st.integers(), st.integers()) def test_addition_commutative(a, b): """Property: addition is commutative.""" assert a + b == b + a @given(st.lists(st.integers())) def test_sorted_list_properties(lst): """Property: sorted list is ordered.""" sorted_lst = sorted(lst) # Same length assert len(sorted_lst) == len(lst) # All elements present assert set(sorted_lst) == set(lst) # Is ordered for i in range(len(sorted_lst) - 1): assert sorted_lst[i] <= sorted_lst[i + 1]

写法与含义:

  • @given(st.text())/@given(st.integers())/@given(st.lists(st.integers())):声明输入策略,Hypothesis 会为每次测试生成大量随机样例(包括空字符串、空列表、负整数、大整数等边界);
  • 四个测试分别验证四条不变量:反转两次还原、长度不变、加法交换律、排序后"长度相同 + 元素集合相同 + 单调非递减"。特别是set(sorted_lst) == set(lst)巧妙地用集合去重后的相等性证明了"排序不丢元素"(注意:若列表含重复元素,该断言仍成立,因为排序前后的多重集相等——sorted是稳定重排);
  • 属性测试的哲学是"你写性质,框架找反例"。一旦发现反例,Hypothesis 会报告最小化后的失败输入,帮助快速定位 bug,这是穷举式示例测试无法提供的回报。

八、数据库代码测试:内存数据库与唯一约束

数据库测试的黄金实践是"用 SQLite 内存库替代真实数据库"——零配置、速度快、测试结束自动销毁。本模式的db_sessionfixture 采用scope="function",保证每个测试都拿到全新的数据库,彻底隔离状态。

# test_database_models.py import pytest from sqlalchemy import create_engine, Column, Integer, String from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker, Session Base = declarative_base() class User(Base): """User model.""" __tablename__ = "users" id = Column(Integer, primary_key=True) name = Column(String(50)) email = Column(String(100), unique=True) @pytest.fixture(scope="function") def db_session() -> Session: """Create in-memory database for testing.""" engine = create_engine("sqlite:///:memory:") Base.metadata.create_all(engine) SessionLocal = sessionmaker(bind=engine) session = SessionLocal() yield session session.close() def test_create_user(db_session): """Test creating a user.""" user = User(name="Test User", email="test@example.com") db_session.add(user) db_session.commit() assert user.id is not None assert user.name == "Test User" def test_query_user(db_session): """Test querying users.""" user1 = User(name="User 1", email="user1@example.com") user2 = User(name="User 2", email="user2@example.com") db_session.add_all([user1, user2]) db_session.commit() users = db_session.query(User).all() assert len(users) == 2 def test_unique_email_constraint(db_session): """Test unique email constraint.""" from sqlalchemy.exc import IntegrityError user1 = User(name="User 1", email="same@example.com") user2 = User(name="User 2", email="same@example.com") db_session.add(user1) db_session.commit() db_session.add(user2) with pytest.raises(IntegrityError): db_session.commit()

三个测试分别覆盖:CRUD 的 C(创建后主键自动生成)、CRUD 的 R(批量插入后查询数量)、约束错误路径(唯一键冲突必须抛IntegrityError)。最后这个测试是数据库测试中最容易遗漏的一环——它验证的是数据库层约束,而非应用层校验,只有真实提交(commit())才会触发。with pytest.raises(IntegrityError)正是 details.md Pattern 5(测试异常)在数据库场景的延伸:异常类型 + 触发时机(commit而非add)都要准确。

从源码结构看,本仓库 plugin-eval 的测试套件同样遵循"测试隔离"原则:其conftest.py通过tmp_path为每个测试构造独立插件目录,本质上是"文件系统版的内存数据库"——两者共享同一设计哲学:测试环境必须廉价、独立、可重复

九、CI/CD 集成:矩阵测试与覆盖率上报

测试的价值在本地单人环境是有限的,在 CI 中持续运行才能守住质量底线。本模式给出标准的 GitHub Actions 工作流,其核心是matrix 矩阵策略——同一套测试在多版本 Python 上并行运行。

# .github/workflows/test.yml name: Tests on: [push, pull_request] jobs: test: runs-on: ubuntu-latest strategy: matrix: python-version: ["3.9", "3.10", "3.11", "3.12"] steps: - uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | pip install -e ".[dev]" pip install pytest pytest-cov - name: Run tests run: | pytest --cov=myapp --cov-report=xml - name: Upload coverage uses: codecov/codecov-action@v3 with: file: ./coverage.xml

流程拆解与工程要点:

  • on: [push, pull_request]:每次推送与每个 PR 都触发,确保合入前质量门禁生效;
  • strategy.matrix.python-version声明 3.9–3.12 四个版本,GitHub Actions 自动展开为 4 个并行 job,验证跨版本兼容性(本仓库 plugin-eval 要求requires-python = ">=3.12",实际矩阵范围应与其声明的支持范围一致);
  • pip install -e ".[dev]":以可编辑模式安装包并带上 dev 可选依赖——对应 plugin-eval 的 pyproject.toml 中[project.optional-dependencies].dev的用法;
  • pytest --cov=myapp --cov-report=xml:运行测试并输出 Cobertura 格式覆盖率文件coverage.xml
  • 最后一步将覆盖率上传到 Codecov 等平台,形成 PR 覆盖率趋势。若没有外部平台,也可以改用--cov-fail-under=80让 CI 在覆盖率低于阈值时直接失败(见 SKILL.md 的覆盖率一节)。

十、pytest 配置文件:pytest.ini 与 pyproject.toml 两种风格

pytest 支持多种配置载体,最常用的是pytest.inipyproject.toml。二者表达同一套配置,但现代项目更倾向把配置统一收进pyproject.toml,减少根目录散落文件。本模式两种写法都给出,方便不同项目风格对号入座。

10.1 pytest.ini 风格

# pytest.ini [pytest] testpaths = tests python_files = test_*.py python_classes = Test* python_functions = test_* addopts = -v --strict-markers --tb=short --cov=myapp --cov-report=term-missing markers = slow: marks tests as slow integration: marks integration tests unit: marks unit tests e2e: marks end-to-end tests

配置项语义:

  • testpaths:指定测试发现根目录,避免 pytest 误扫 venv 等无关目录;
  • python_files/python_classes/python_functions:测试文件、类、函数的默认匹配模式,与 SKILL.md 的命名规范(test_<unit>_<scenario>_<expected>)配套使用;
  • addopts:每次运行时自动追加的命令行参数。--strict-markers要求所有 marker 必须先注册(未注册即报错,防止拼写错误),--tb=short精简回溯,--cov--cov-report=term-missing让每次测试都在终端输出缺失行;
  • markers:集中注册slowintegrationunite2e等标记。注册后即可配合 SKILL.md 中的 marker 用法执行pytest -m slow(只跑慢测试)、pytest -m "not slow"(跳过慢测试)等选择性运行。

10.2 pyproject.toml 风格

# pyproject.toml [tool.pytest.ini_options] testpaths = ["tests"] python_files = ["test_*.py"] addopts = [ "-v", "--cov=myapp", "--cov-report=term-missing", ] [tool.coverage.run] source = ["myapp"] omit = ["*/tests/*", "*/migrations/*"] [tool.coverage.report] exclude_lines = [ "pragma: no cover", "def __repr__", "raise AssertionError", "raise NotImplementedError", ]

pytest.ini等价但使用 TOML 数组语法,并额外管理 coverage 配置:

  • [tool.coverage.run].source:只统计myapp包的覆盖率,排除依赖与框架代码;
  • [tool.coverage.run].omit:剔除测试代码与迁移脚本,避免"测试代码本身"污染覆盖率数字;
  • [tool.coverage.report].exclude_lines:声明不计入覆盖率的行模式——pragma: no cover是显式忽略标记,def __repr__raise AssertionErrorraise NotImplementedError则自动排除"调试友好型"或"永远不会走到"的样板代码,防止覆盖率虚高或虚低。

仓库佐证:本仓库 plugin-eval/pyproject.toml 正是采用第二种风格的真实案例:

[tool.pytest.ini_options] testpaths = ["tests"] asyncio_mode = "auto"

它在pytest.ini_options中额外声明了asyncio_mode = "auto",与本文 Pattern 6 的异步测试直接呼应——这也是为什么其测试套件(plugins/plugin-eval/tests/下的十余个test_*.py文件)可以混写同步与异步测试而无需逐个打装饰器。

十一、组合应用:一个完整的进阶测试工作流

将上述模式串联起来,一个生产级 Python 测试套件的标准形态是:

  1. 目录结构按 SKILL.md 建议分层:tests/conftest.py放共享 fixture,test_unit/test_integration/test_e2e/分目录组织;
  2. 共享 fixture(Pattern 9)放入conftest.py,需要tmp_path(Pattern 8)的就注入它,需要环境隔离的就用 monkeypatch(Pattern 7);
  3. 异步业务代码@pytest.mark.asyncioasyncio_mode = "auto"测试(Pattern 6),并用asyncio.gather验证并发正确性;
  4. 算法与数据逻辑补充属性测试(Pattern 10),用 Hypothesis 挖掘示例测试发现不了的反例;
  5. 数据库层用 function 级内存库 fixture 覆盖 CRUD 与约束错误(Pattern 8 的数据库变体);
  6. 配置统一写进pyproject.toml(Pattern 8 的配置节),testpathsaddopts、coverage 排除规则一并在版本控制中沉淀;
  7. CI(Pattern 8 的 CI/CD 节)用矩阵在多个 Python 版本上并行跑同一套测试,并上传覆盖率。

本仓库 plugin-eval 的测试套件即可视为这一工作流的缩影:conftest.py定义基于tmp_path的组合 fixture,pyproject.toml统一配置 pytest 选项,测试文件覆盖 CLI、语料解析、ELO 评分引擎、裁判模型等模块。阅读这些测试(例如 tests/conftest.py 与 tests/test_cli.py)是理解本文各模式在生产代码中落地方式的最佳捷径。

十二、总结

本文系统讲解了 advanced-patterns.md 的六大进阶主题:异步测试(pytest-asyncio+ 并发 + 异步 fixture)、monkeypatch(环境变量与属性的安全篡改与自动还原)、tmp_path临时文件隔离、conftest 共享 fixture(scope、autouse、参数化)、Hypothesis 属性测试,以及数据库内存库测试、CI 矩阵与双风格配置文件。配合 details.md 的基础模式(fixture 生命周期、参数化、mock、异常测试)与 SKILL.md 的最佳实践(AAA 结构、命名规范、测试隔离、marker、覆盖率阈值),即可构建一套覆盖单元到集成、同步到异步、逻辑到数据的完整 pytest 测试体系。这些模式在本仓库 plugin-eval 项目中均有对应落地实现,可作为参照模板直接迁移到你的项目。

【免费下载链接】agentsMulti-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity项目地址: https://gitcode.com/GitHub_Trending/agents24/agents

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询