
开发工具【免费下载链接】PyGithubTyped interactions with the GitHub API v3项目地址https://gitcode.com/gh_mirrors/py/PyGithub点击查看免费下载本篇指南围绕 PyGithub 官方文档 doc/testing.rst 展开系统讲解如何在本仓库中安装测试依赖、运行与定位单个测试、通过--record录制 GitHub REST API 的 Replay Data 回放数据、为不同认证模式token/JWT/App/无认证编写测试以及如何借助 scripts/prepare-for-update-assertions.py 与 scripts/update-assertions.sh 自动更新断言。读完本文你将掌握 PyGithub 完整测试链路的工作原理与实操流程能够为本仓库新增或修改测试并提交合规的 Replay Data 文件。一、测试环境准备与基础运行PyGithub 的自动化测试基于pytest构建测试依赖统一声明在 requirements/test.txt 中。先安装测试依赖pip install -r requirements/test.txt该文件明确列出了测试所需的最小依赖集合依赖包作用pytest5.3测试运行器pytest-cov2.8覆盖率统计--covgithubpytest-subtests0.11.0子测试支持pytest-github-actions-annotate-failures1.0.0CI 失败注解responses拦截并模拟 HTTP 请求响应Replay 模式的核心支撑parameterized参数化测试用例more-itertools迭代工具补充依赖安装完成后运行整个测试套件pytest testspytest 的相关配置集中在 pyproject.toml 的[tool.pytest.ini_options]中python_files tests/*.py限定测试文件匹配规则addopts --coloryes --ignoreopenapi默认开启彩色输出并跳过openapi目录。运行单个测试的三种方式按文件粒度、按方法名、按类名.方法名三种方式均可精确定位# 运行某个测试文件中的全部测试 pytest tests/tests_filename.py # 运行该文件中名称匹配 testMethod 的测试-k 支持关键字过滤 pytest tests/tests_filename.py -k testMethod # 运行指定测试类的指定测试方法 pytest -k TestClass.testMethod例如要只运行Repository.testCompare可执行pytest -k Repository.testCompare注意仓库中测试文件本身不带tests_前缀例如 tests/Repository.py-k匹配的是测试类名与方法名。手动测试开发版可编辑安装如果希望用本地开发版本配合外部脚本做手动测试即“边改边测”修改源码后无需重新安装使用可编辑安装pip install --editable path/to/project将path/to/project替换为本仓库的绝对路径。可编辑安装会把github包以链接方式注册进当前 Python 环境任何源码改动都会即时反映到外部脚本中。使用 tox 运行测试仓库同时提供了 tox.ini 用于多环境测试。其envlist覆盖lint、py{310-315}Python 3.10 至 3.15以及docs环境。testenv默认执行的命令是commands pytest --junit-xml pytest.xml --covgithub --cov-reportxml {posargs}即运行测试的同时生成 JUnit XML 报告与 XML 覆盖率报告。按文档示例运行指定 Python 版本pip install tox tox -epy313tox.ini中[gh-actions]一节将 CI 矩阵中的 Python 版本映射到对应 tox 环境如3.13: py313保证本地与 CI 行为一致[testenv:lint]额外执行pre-commit run --all-files与mypy github tests[testenv:docs]则用sphinx-build doc build构建文档。二、Replay Data拦截式测试的基石PyGithub 的绝大多数测试都会真实调用 GitHub REST API但这会带来网络依赖、限流与数据漂移问题。因此测试框架采用“录制-回放”Record Replay策略其核心约定出自 doc/testing.rst是测试环境会拦截这些 API 调用断言调用与预期一致然后返回预先录制的 GitHub API 数据测试再对这些返回数据断言其符合预期值。这套机制的源码实现位于 tests/Framework.py可以从代码层面理解其工作原理连接类注入BasicTestCase.setUp()根据recordMode标志通过github.Requester.Requester.injectConnectionClasses(...)把github/Requester.py默认的 HTTP 连接类替换为RecordingHttpConnection/RecordingHttpsConnection录制模式或ReplayingHttpConnection/ReplayingHttpsConnection回放模式。录制连接RecordingConnection在真实发出请求前把协议、HTTP 动词、主机、端口、URL、请求头、请求体逐行写入 Replay 文件收到响应后再写入状态码、响应头与响应体行与行之间以空行分隔。回放连接ReplayingConnection借助responses库注册回调将当前请求与 Replay 文件中记录的请求逐字段比对协议、动词、主机、端口、URL、请求头、请求体比对失败抛出Replay data mismatch in {file}匹配成功后返回文件中记录的响应。令牌脱敏fixAuthorizationHeader会在录制前把真实 Authorization 头替换为token private_token_removed、Basic login_and_password_removed、Bearer jwt_removed避免凭据写入版本库。Replay 文件的物理格式可以从 tests/ReplayData/Repository.testCompare.txt 直接观察到前 7 行依次是协议(https)、动词(GET)、主机(api.github.com)、端口(None)、URL(/repos/PyGithub/PyGithub/compare/v0.6...v0.7?page1)、请求头字典、请求体(None)随后是200状态码、响应头字典、JSON 响应体与空行。Replay 数据目录位于 tests/ReplayData与测试文件一一对应例如 tests/Repository.py 的testCompare对应 tests/ReplayData/Repository.testCompare.txt。三、录制新的 Replay Data当你新增或修改一个测试例如Repository.testCompare时必须先录制新的回放数据。文档给出的命令是pytest -k Repository.testCompare --record--record是一个 pytest 自定义选项定义于 tests/conftest.pydef pytest_addoption(parser): parser.addoption(--record, actionstore_true, helprecord mode) def pytest_configure(config): if config.getoption(record): Framework.activateRecordMode()传入--record后Framework.activateRecordMode()会把BasicTestCase.recordMode置为True测试随即以真实网络请求录制数据。执行成功后会在tests/ReplayData/下创建或更新对应文件——例如 tests/ReplayData/Repository.testCompare.txt。该文件必须随测试一起加入 git 并提交否则 CI 或其他开发者无法回放运行你的测试。文件名由Framework.BasicTestCase.__openFile自动推导从调用栈中查找以test开头或名为setUp/tearDown的函数名组合为{测试类名}.{函数名}.txt如Repository.testCompare.txt。因此一个测试方法默认对应一个独立的 Replay 文件。录制模式有一个前置条件需要真实的 GitHub 凭据详见下一节“认证测试”。四、Replay 文件复用避免重复数据每个测试默认拥有自己的 Replay 数据文件但如果两个测试调用的是同一接口例如testCompare与testCompare2都调用repo.compare(v0.6, v0.7)为避免重复数据文件可以显式复用另一个测试的回放文件。文档给出的完整示例为class Repository(Framework.TestCase): def setUp(self): # this method uses file Repository.setUp.txt super().setUp() self.repo self.g.get_repo(PyGithub/PyGithub) def testCompare(self): # this method uses file Repository.testCompare.txt comparison self.repo.compare(v0.6, v0.7) self.assertEqual(comparison.status, ahead) def testCompare2(self): # this method would use file Repository.testCompare2.txt # but here we explicitly reuse a different file with self.replayData(Repository.testCompare.txt): comparison self.repo.compare(v0.6, v0.7) self.assertEqual(comparison.status, ahead)关键点是self.replayData(...)上下文管理器定义于 tests/Framework.py 的BasicTestCase它临时改写__customFilename使当前作用域内的请求读取指定 Replay 文件作用域结束后自动还原。与之配套setUp阶段获取仓库对象会使用Repository.setUp.txt可对照 tests/ReplayData/Repository.setUp.txt其中记录了GET /repos/PyGithub/PyGithub的响应。此外Framework.TestCase还提供assertListKeyEqual/assertListKeyBegin等列表断言辅助方法以及captureRequests()上下文管理器用于捕获测试过程中实际发出的请求对象。五、认证测试四种 authMode绝大多数 GitHub API 调用需要认证而录制 Replay 数据时更是必须持有真实凭据。录制模式下需要在仓库根目录创建GithubCredentials.py内容如下出自 doc/testing.rstoauth_token my_token jwt my_json_web_token # Can be left empty if not used app_id my_app_id # Can be left empty if not used app_private_key my_app_private_key # Can be left empty if not usedoauth_token是录制数据的默认认证方式需要 JWT、App 认证或完全无认证的测试类必须在各自的setUp方法中显式启用对应模式。在测试类的setUp中通过设置self.authMode切换认证模式可选值为jwt、app、none默认是token即使用oauth_token。源码层面tests/Framework.py 的BasicTestCase.__init__将authMode初始化为tokenTestCase.get_github(authMode, retry, pool_size)则根据模式构造github.Github(authauth, per_page..., retry..., pool_size..., seconds_between_requests..., seconds_between_writes...)实例其中none模式下auth为None。录制时GithubCredentials中的字段会被转换为github.Auth.Token/github.Auth.AppAuthToken/github.Auth.AppAuth认证对象。def setUp(self): self.authMode jwt super().setUp() ...单个测试方法需要与setUp配置不同认证时不必改动类级配置只需在该方法内用self.get_github(...)新建Github对象def setUp(self): self.authMode none super().setUp() def testGetUserWithoutAuth(self): # this test uses no authentication self.assertEqual(self.g.get_user(jacquev6).name, Vincent Jacques) def testGetUserWithOAuth(self): # this test needs OAuth authentication g self.get_github(oauth_token) self.assertEqual(g.get_user(jacquev6).name, Vincent Jacques) def testGetUserWithJwt(self): # this test needs JWT authentication g self.get_github(jwt) self.assertEqual(g.get_user(jacquev6).name, Vincent Jacques) def testGetUserWithAppAuth(self): # this test needs App authentication g self.get_github(app) self.assertEqual(g.get_user(jacquev6).name, App name)注意self.g与self.get_github(...)的区别Framework.TestCase.setUp会在记录模式下按authMode自动创建self.g并开启GithubObject的checkAfterInitFlag与Requester的debugFlag帧级调试而get_github允许按需创建带指定认证的独立实例。另外回放非录制模式下框架会自动构造占位认证对象github.Auth.Token(oauth_token)等因此普通测试运行不需要真实凭据无需创建GithubCredentials.py。六、更新断言自动化处理 Replay 数据变动录制数据更新后测试断言可能因 GitHub 侧字段值变化而失败。文档建议的处理流程分三步全部可自动执行# 1) 将多行断言转换为单行为脚本处理做准备 python ./scripts/prepare-for-update-assertions.py # 2) 用实际值更新期望值脚本无法修复的行请手动修正然后重跑该命令 ./scripts/update-assertions.sh tests/Repository.py testCompare # 3) 重新格式化测试文件按需恢复多行断言 pre-commit run --all-files第一步prepare-for-update-assertions.pyscripts/prepare-for-update-assertions.py 基于libcstPython 语法树解析库实现SingleLineStatementTransformer会把指定测试函数内的所有函数调用、参数、括号、逗号等节点的空白符压缩为单行从而让每个断言变成一行便于第二步的 sed 正则定位。脚本支持--dry-run只展示差异不写文件与--exit-code有变更时以非零码退出供 CI 使用同时不传入参数时会打印帮助信息。第二步update-assertions.shscripts/update-assertions.sh 接收两个参数测试文件与测试函数名其工作方式为生成临时conftest.py将unittest.util._MAX_LENGTH调大到 10240避免 unittest 缩写实际的/期望的值循环执行pytest --colorno test_file -k test_func从输出中 grepAttributeError/AssertionError行解析出行号与“实际值 ! 期望值”用sed把对应行的期望值替换为实际值None期望被替换为assertIsNone(...)被截断的字符串替换为assertTrue(x.startswith(...))普通值直接替换进断言参数遇到无法自动修复的行如授权错误会报告并提示手动修正后重跑同一行连续两次未修复则退出。脚本还特意在运行前写入的conftest.py位于仓库根目录——运行结束后该临时文件会保留在当前工作目录可手动清理。第三步pre-commit 格式化仓库根目录存在 .pre-commit-config.yamlpre-commit run --all-files会执行 lint 工具链black 等格式化工具行宽 120见 pyproject.toml 的[tool.black]与[tool.ruff]配置将单行断言在必要时恢复为符合风格的多行形式并校验整个仓库的格式。七、测试约定与工作流小结综合以上内容PyGithub 的测试开发工作流可以归纳为准备环境pip install -r requirements/test.txt需要构建文档或多版本矩阵时再安装tox日常回归pytest tests或pytest -k TestClass.testMethod精准定位回放模式无需网络与凭据新增/修改测试在仓库根目录准备GithubCredentials.py含真实oauth_token等用pytest -k 测试名 --record录制 Replay 数据并将生成的tests/ReplayData/*.txt一并提交根据测试所需的认证方式在setUp中设置self.authMode或在该方法内用self.get_github(...)按需创建认证实例需要复用已有数据时用self.replayData(已有文件名.txt)包裹调用处理数据漂移先运行python ./scripts/prepare-for-update-assertions.py压缩断言为单行再运行./scripts/update-assertions.sh tests/xxx.py testXxx自动替换期望值手动修复脚本无法处理的行后重跑最后pre-commit run --all-files恢复格式化CI 一致校验提交前可用tox跑完整环境矩阵与 lint/mypy确保与 tox.ini 中 CI 配置一致。理解这一套机制的关键在于把握 tests/Framework.py 中“连接类注入 逐行回放比对 认证对象按模式切换”的三角结构Replay Data 不仅是测试夹具更是整个测试套件离线化、确定化运行的保证而 tests/ReplayData 目录中近千个.txt文件正是这套机制长期积累的产物。赞分享开发工具【免费下载链接】PyGithubTyped interactions with the GitHub API v3项目地址https://gitcode.com/gh_mirrors/py/PyGithub点击查看免费下载相关推荐ZAP Docker 测试框架完全指南suite.py 自动发现机制与测试编写实战ZAP Docker 测试框架完全指南suite.py 自动发现机制与测试编写实战 本指南以 ZAPZaproxy仓库中 docker/tests/REA网络安全应用安全开发工具Gradio 前端 E2E 测试实战基于 Playwright 的断言、调试与测试编写指南Gradio 前端 E2E 测试实战基于 Playwright 的断言、调试与测试编写指南 本篇技术指南以 Gradio 仓库中的 testing guide前端后端AI 应用Playwright C 测试编写指南自动等待、Locator 操作、Expect 断言与测试隔离Playwright C 测试编写指南自动等待、Locator 操作、Expect 断言与测试隔离 本篇指南基于 Playwright 官方文档 Writin测试开发工具浏览器控制上一篇AtlasOS电源管理优化解锁Windows性能与能效的完美平衡下一篇Windows终极优化指南用WinUtil一键解决系统管理难题创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考