从临时脚本到自动化测试工程:pytest框架下的稳定用例设计与数据管理
“test004”这个项目编号乍看像随手敲出来的临时文件夹名称但如果你真的在团队或自己的仓库里建到第四个以 test 开头的工程多半已经踩过不少坑了。我最近在整理手头这个 test004 项目时正好把它从“验证某个想法能不能跑”的试验田沉淀成了一套可以反复使用的自动化测试基础骨架。这篇文章就围绕这个编号背后真正值得聊的东西展开测试工程怎么搭、用例怎么设计、数据怎么管、遇到偶发失败怎么排查。内容偏实操适合正在从零搭建自动化测试体系、或者写了脚本但始终稳定不下来的测试开发与后端工程师参考。1. 项目定位从“跑一次”到“一直能跑”1.1 测试项目编号背后隐藏的分层策略拿 test004 来说前面的 test001、test002 并不是简单复制粘贴。它们实际上承担了完全不同的验证职责test001 可能是临时验证某个第三方 SDK 的连通性test002 验证某个数据库驱动在特定版本下的行为test003 是验证 CI 流水线上缓存策略是否生效到 test004 才真正开始沉淀通用测试框架。如果你仔细看每个测试工程的改动历史会发现越往后代码越趋向于“消除环境差异”而不是“堆功能”。这个分层过程很重要但很多人恰恰会在第一步就拆错方向。最常见的做法是建一个名为 tests 的目录然后把所有验证逻辑塞进去过三个月后里面的文件连作者自己都不敢动。我后来总结出一个小原则以稳定边界划分测试工程而不是以业务模块划分。也就是说凡是需要依赖外部资源数据库、缓存、文件系统、第三方服务的验证和只依赖内存对象与纯函数的验证必须分在不同层级的目录里。否则你会遭遇一种特别难受的情况业务代码明明没改动测试却因为开发环境网络抖动全军覆没。test004 这个项目之所以能走到第四轮是因为我给它设了一条硬性边界不验证任何真实的第三方服务只验我们自己代码的行为以及我们自己对第三方服务的封装是否正确。这条边界让它的稳定率在很长一段时间里保持在接近满分也让后面的排错速度变得快很多。1.2 什么时候你才真正需要一个独立测试工程一个常见问题脚本能跑不就行了为什么要单独搞一个工程出来我的判断标准很直接当同一个用例需要被跑第二遍并且第二遍和第一遍之间间隔超过一周时它就应该被搬进正式测试工程。因为脚本时代你依赖的是当时的记忆而工程时代你依赖的是代码本身的可读性和可复现性。test004 里的用例很多都是从临时脚本里迁过来的迁移过程中顺手修复了至少三个只有原作者才知道的隐性假设。比如有一个用例原本校验用户登录成功后返回的 token 长度当时脚本里写死是 32 位。等到我把这个脚本迁入工程时token 早就变成了结构化的 JWT长度也变了。如果只靠记忆这类问题根本不会被发现但当你把断言、数据、操作步骤分开管理后翻看代码时就能立刻意识到“这里的硬编码长度是个需要问清楚的点”。独立测试工程另一个价值在于它能捎带锻炼代码设计能力。测试代码同样需要抽象、复用和可读性这种能力不会因为在业务代码里写过几年 CRUD 就自动具备。2. 测试脚本与测试工程的分水岭在哪里2.1 可重复、可报告、可维护很多团队把“测试脚本”和“测试工程”混为一谈但实际差别非常大。一条一条捋下来主要是三个方面。可重复是一切的地基。脚本时代你可能跑一次就删了或者跑完就忘。工程化之后用例必须能反复执行、结果一致。我见过太多测试被写成“依赖上一个用例的结果”顺序一乱就翻车。这种耦合在脚本里还能忍规模一上来就是灾难。test004 里我强制要求每个用例都是独立可执行的哪怕是需要登录态的用例也通过 fixture 自己完成登录准备而不是依赖一个全局登录标记。这带来了一个额外的好处很多用例开始可以并行执行了。可报告是容易忽略的一环。脚本时代看打印日志工程时代必须要有一份结构化报告包含了哪些用例通过、哪些失败、失败原因的大致分类。test004 里我用 pytest 本身的结果输出再加上在每个关键步骤埋了结构化日志。报告的意义不仅是给人看更重要的是给历史留痕。遇到过线上问题后翻三个月前的测试报告能直接定位到当时的系统状态和测试结果这个价值远比省下五分钟运行时间大。如果你觉得“反正我本地跑跑看结果就行”那说明你还没有被半夜线上事故拷打过。可维护听起来虚实际上可以量化修改一个接口字段名需要改动多少处测试代码。理想状态是控制在少量几处。test004 的做法是定义了一层轻量级的业务操作封装不直接在各种用例里散落地写 HTTP 调用细节。这样接口字段调整时只需要改封装层和测试数据工厂而不是翻遍几十个用例去做文本替换。2.2 独立工程带来的成本和收益对比独立测试工程不是没有代价的它需要单独维护依赖、环境配置、CI 任务。但收益非常明确用一个表格可以看得很清楚维度脚本式验证独立测试工程用例复用低复制粘贴为主高装饰器和 fixture 沉淀失败定位靠肉眼盯日志靠断言栈和报告聚合环境漂移影响每台机器结果都不同通过 conftest 统一基线执行成本全量重跑靠人工按标记挑选用例秒级反馈交接成本作者离职即失传新人看命名和注释可维护这个表不是想说明独立工程天生优越而是想帮你判断如果你只是在做一次性数据校验写脚本完全没问题如果你维护的系统会持续演进超过半年那独立测试工程的收益一定会盖过初期建造成本。test004 建立初期我大概花了两个下午做目录、依赖和基础 fixture 的梳理后续几乎每天都在享受这个设计的红利——比如本地改完代码后在命令行敲一句 pytest -m not integration 就能在三分钟内得到基础回归结论而不是打开 Postman 手动点十几个接口。3. 搭建一套可复用的测试骨架3.1 目录结构与依赖设计先给出一个我实际使用下来很舒服的目录结构test004 就是按这个结构整理的test004/ ├── pyproject.toml ├── pytest.ini ├── README.md ├── src/ │ └── demo_app/ │ ├── __init__.py │ ├── calculator.py │ └── api_client.py └── tests/ ├── conftest.py ├── factories/ │ ├── __init__.py │ └── user_factory.py ├── unit/ │ └── test_calculator.py └── integration/ └── test_api_client.py我把被测代码放在 src 目录下而不是和测试代码混在一起这样能强制测试从“使用者的视角”导入包避免了测试直接触碰内部实现细节。很多初学者喜欢把被测函数直接复制进测试文件里这会让测试完全失去价值——你等于在验证一份和线上代码不相干的拷贝。依赖管理上test004 选用的是 pyproject.toml 单文件方案把运行依赖和测试依赖分开声明。这样做的好处是后续如果有人要用 CI直接安装同一个文件就能复现环境不需要额外看一篇环境搭建文档。个人体会是测试依赖务必锁定版本范围。pytest 这类工具的版本升级经常会带来插件兼容性变化锁太死会导致安全修复困难完全不锁又会让某个周末突然跑挂一批用例。折中方案是把主版本号固定、次版本以上浮动然后定期手动升级验证。3.2 环境隔离与基础配置本地调试时我的习惯是创建虚拟环境不直接装进全局 Python 环境。具体命令很简单python -m venv .venv source .venv/bin/activate pip install -e .[dev]其中 pyproject.toml 里的测试特性部分大致长这样[project.optional-dependencies] dev [ pytest8.0,9.0, pytest-cov5.0,6.0, pytest-xdist3.0,4.0, ]接着在 pytest.ini 里做最基础的配置。我建议至少要配两个参数testpaths和markers。testpaths告诉 pytest 去哪找用例markers用于登记自定义标记避免运行时有莫名奇妙的 warning。[pytest] testpaths tests markers integration: marks tests that require external dependencies smoke: quick smoke tests addopts -ra --strict-markers这里--strict-markers非常有用它会在你使用未登记的标记时直接报错相当于强迫团队把每个标记的用途讲清楚。在 test004 中我把冒烟用例和集成用例做了标记区分本地开发只跑冒烟提交前再跑全量集成这让反馈速度和覆盖范围可以兼得。3.3 写第一个带断言的用例test004 里最简单的被测模块是一个计算器类对应的测试用例几乎可以作为所有单测的模板# src/demo_app/calculator.py class Calculator: def add(self, a: int, b: int) - int: return a b # tests/unit/test_calculator.py from demo_app.calculator import Calculator def test_add_numbers(): calc Calculator() result calc.add(2, 3) assert result 5注意这个用例里其实没有刻意去测“2 3 等于 5”这个算术常识而是在验证Calculator.add这个函数真的通过公开入口完成了加法操作。很多人在写这种用例时会犯一个毛病直接测试实现细节比如检查内部某个临时变量被赋成了什么值。那样一旦重构用例会集体阵亡。好的单测应只关注“输入”和“输出”而不是“中间经过了多少步”。同时assert 越具体越好。test004 中对返回字典的断言我不会只写assert response is not None而是会明确断言需要被保证的关键字段和数值。比如校验一个创建用户的接口至少会检查用户 id 存在、名字正确、状态字段符合预期。模糊断言会让用例产出一种“绿了但不知道绿在哪”的错觉排查时反而更浪费时间。4. 测试数据与用例设计里的几件“小事”4.1 工厂函数的作用不止是造数据许多测试新手会在每个用例里直接写一堆字典变量试着覆盖系统需要的各种字段。一旦字段结构发生调整所有用例里的字典都得改一遍。test004 里我用的是工厂函数的方式典型实现如下# tests/factories/user_factory.py def make_user(overrides: dict None): user { name: tester, email: testerexample.com, role: member, } if overrides: user.update(overrides) return user使用时只需要按需覆盖def test_admin_user_has_admin_role(): user make_user({role: admin}) assert user[role] admin这种方式的好处是默认值集中维护用例只描述“自己关心的差异”。这个思路有点像生活中的“标准化套餐”——基础汉堡永远不变你只需要选要不要加芝士。它避免了每个用例都从零搭建数据的重复代码也让测试意图变得更清晰看用例时一眼就知道它在意的是 admin 角色这个差异点而不是被迫阅读整段又长又无关的数据结构。4.2 断言设计最容易踩的四个坑第一个坑是对异常行为的断言过于宽松。比如用 pytest 的pytest.raises(Exception)一把梭这样写等于告诉系统“出什么错我都会放行”根本没法验证错误处理逻辑是否正确。应该尽量断言具体异常类型比如ValueError或KeyError甚至进一步断言异常消息里的关键字。第二个坑是对浮动结果直接做相等断言。如果被测函数返回的是一个时间戳、一个临时文件名或者带随机后缀的资源 ID那么每次运行的输出都不一样。针对这种场景我通常会把断言拆成两段先断言结构例如等于长度为 32 的字符串、时间戳能解析再断言关联逻辑例如字段 A 变化时字段 B 跟着变化。第三个坑是断言写得太靠后。有些用例运行了几十秒的流程最后才 assert 一个结果一旦失败中间过程完全不可见。我习惯在关键步骤后立刻加状态断言宁可多写几个 assert也不要让排查者从一道长长的输出日志里寻找案发地点。第四个坑是无视超时和并发。在 test004 的集成用例中所有对外部服务的调用都配置了超时时间并且在断言前设置了等待条件而不是直接sleep(10)写死。sleep 会让用例变慢而且换一个环境后可能超时时间不够反而制造出偶发性失败。你可以用pytest的pytest-timeout插件做兜底但更重要的是让代码本身对“还没好”这件事有合理的轮询和重试策略。4.3 数据清理的顺序为什么重要集成测试里不可避免会创建真实数据测试结束后的清理顺序可以直接影响后续用例的稳定性。test004 给我的教训是先清理依赖数据再清理主数据。举例来说一个订单系统里订单依赖用户和商品那么清理时必须先删订单再删商品和用户否则数据库外键约束会直接拒绝删除抛出异常后又导致测试失败。另外要小心部分清理、部分保留的“脏环境”策略。如果用例之间做数据隔离的代价过高至少要保证每个用例都往自己的命名空间里写数据。例如测试创建订单时用order_uuid作为订单编号而不是固定用order_001。这样即使清理漏了一条也不至于让其他用例读到了错误的关联数据。5. 常见问题与排查技巧实录5.1 偶发失败排查速查表test004 运行期间我遇到过的偶发失败基本集中在三类原因环境状态不一致、测试间相互影响、外部依赖不稳定。下面这张表是我根据实际踩坑整理的快速定位清单现象可能原因排查方向同一个用例在本地通过、CI 失败环境变量或系统时区差异把系统状态写到测试报告里用例单独跑通过、全量跑失败全局状态被其他用例污染检查模块级变量和缓存等待时间不足导致失败外部服务响应慢优化轮询逻辑和超时配置数据库出现莫名重复数据清理逻辑没按顺序执行检查依赖数据的删除顺序断言偶发失败且时间相关系统时钟或 cron 任务干扰打印前后对照时间戳这个表的用途不是一次性解决所有问题而是帮你建立“看到现象先想原因类别”的直觉。很多时候人会被单个失败的报错信息带偏方向最后发现只是环境多跑了一次旧版本代码。5.2 我用过的三个稳定化技巧随机端口绝对是集成测试的首选。无论被测服务是 Web 服务还是内部 RPC 服务都不要使用固定的 8080、9090 等端口因为你不知道本地或 CI 机器上会不会有别的进程占着它。test004 里我封装了一个端口分配函数在启动服务前随机找空闲端口然后通过环境变量传给服务进程。这样执行环境几乎不会被端口冲突命中。结构化日志回传。每当用例失败时除了打印异常堆栈还要把被测服务的关键日志一起聚合到测试报告里。第一次我实现时感觉代码量变多了但后来调试线上问题时才发现它真能救命。没有日志回传时测试报了个连接拒绝但连接到底为什么被拒、服务是否正常启动完全只能靠猜。失败用例自动重试要谨慎。有些团队图省事给所有用例加上“失败自动重跑 3 次”的机制这会让偶发问题神隐不见而且延长整轮测试时间。我支持的做法是只对明确知道的外部依赖脆弱型用例开重试并且给重试行为打上标记后续专门分析这些重试用例是否需要从根源上修稳定。5.3 我踩过的三个坑希望你不要重蹈第一个坑是共享全局配置对象。早期 test004 里的多个测试文件会导入同一个配置常量模块本来只是存几个路径后来有人往里加了包含登录态的字典结果某个用例改了它其他用例全跟着遭殃。解决方式是所有可变状态都收敛进 fixture并且 fixture 的返回对象是全新的不允许跨用例共享。第二个坑是用 sleep 硬等异步任务完成。我刚开始写集成用例时习惯在发起异步任务后 sleep 五秒再断言结果。后来异步任务执行时间从三秒波动到七秒本地一半时间能过一半时间挂掉我开始怀疑代码写错了。最后改成轮询等待 超时上限才真正解决。这个教训总结成一句话不要和真实时间赛跑要和业务完成信号赛跑。第三个坑是只在本机跑一遍就觉得万事大吉。有一次我在 Mac 上把集成测试全部跑绿提交到 CI 的 Linux 环境后立刻挂了一整片原因是我在测试代码里用了/tmp硬编码路径但又假设该路径始终存在而 Linux 环境的临时目录清理策略更激进。从那天开始我立了一条规矩用例里所有文件路径必须由 fixture 动态生成并主动创建绝不假设目录已经存在。6. 从 test004 延伸出去一套可复用的日常检查清单如果让我把 test004 里沉淀出的经验浓缩成一份可以直接抄走的清单大概是这样测试目录划分以依赖边界为准外部依赖和不依赖外部资源的用例分开放。被测代码通过包导入绝不复制粘贴进测试文件。测试断言尽量具体异常断言要指明预期异常类型。数据准备使用工厂函数并支持按需覆盖。一切可变的全局状态都收进 fixture且每个 fixture 返回独立对象。清理数据遵循先子后父的顺序避免外键约束报错。集成测试使用随机端口、动态路径、轮询超时绝不使用固定资源。测试报告里除了断言结果还要提供运行环境摘要与结构化日志。顺着这份清单检查我后来新建的其他工程项目基本没有重蹈 test004 之前的覆辙新同事接手时也不需要我事无巨细讲一遍来龙去脉。项目编号从 test001 走到 test004最关键的收获反而不是某一项测试技术而是对“什么需要验证、如何验证、如何让验证持续可信”的判断力。如果你也正处在测试工程从混沌到秩序的过渡期不妨把这些朴素的经验直接拿去用剩下的坑踩过了自然会记住。

相关新闻

定积分求圆弧投影面积:对称弓形公式与极限逼近

定积分求圆弧投影面积:对称弓形公式与极限逼近

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 1:30:08 阅读更多 →
自动驾驶多传感器融合核心:扩展卡尔曼滤波器EKF原理与工程实践

自动驾驶多传感器融合核心:扩展卡尔曼滤波器EKF原理与工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 1:30:08 阅读更多 →
国产芯片替代工控机方案怎么选?x86、Arm与RISC-V路线对比与落地实践

国产芯片替代工控机方案怎么选?x86、Arm与RISC-V路线对比与落地实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 1:29:08 阅读更多 →

最新新闻

Win11升级后应用打不开?从升级机制到修复方案全解析

Win11升级后应用打不开?从升级机制到修复方案全解析

最近一段时间,我这边处理最多的求助不是软件本身崩溃,而是同一句话:升完 Win11 之后,XX 应用打不开了。有的是设备厂商的配置工具,点开就没反应;有的是行业软件启动后直接闪退;还有的是虚拟机一…

2026/10/13 2:17:27 阅读更多 →
航空航天大文件可靠上传:分片、续传、校验与协议选型实战

航空航天大文件可靠上传:分片、续传、校验与协议选型实战

卫星过顶窗口就那么十几分钟,链路一抖,传了一半的遥感数据全部清零重来,这种滋味我体会过不止一次。航空航天领域的大文件上传,核心关键词就是可靠性——文件动辄几十GB甚至TB级,链路又是高延迟、易抖动的无线环境&…

2026/10/13 2:17:27 阅读更多 →
图片资产CLI管理工具ImgBin:设计、实操与踩坑全记录

图片资产CLI管理工具ImgBin:设计、实操与踩坑全记录

“ImgBin”这个名字,是我在 HagiCode 项目里给图片资产管理工具起的称号,初看像是“图片回收站”,实际却是一个给团队管图片的 CLI 终端程序。HagiCode 是一个对图片依赖很重的项目:界面要出设计稿,文档要写教程&#…

2026/10/13 2:17:27 阅读更多 →
VS2017专用预编译GDAL库:接入配置与避坑指南

VS2017专用预编译GDAL库:接入配置与避坑指南

简介:面向VS2017开发者的预编译GDAL库,省去了在VS2017环境下手动编译GDAL的繁琐过程。包体共6305个文件,以obj目标文件、cpp/c源码、h头文件为主,也包含lib/dll库文件与配置脚本,压缩包约103.88MB。目前已有2108人学习…

2026/10/13 2:17:27 阅读更多 →
排序链表 LeetCode 148:自底向上归并排序 O(1) 空间实现

排序链表 LeetCode 148:自底向上归并排序 O(1) 空间实现

1. 题目剖析:排序链表到底在考什么LeetCode Hot 100里的第148题“排序链表”,表面看起来就是一句话:给一个无序链表排个序。但做过的人都知道,这道题真正难的不是“排序”本身,而是题目附带的两个硬性约束——时间复杂…

2026/10/13 2:17:27 阅读更多 →
MAS v3.12 免费激活 Windows 与 Office 快速教程:一条命令去掉未激活水印

MAS v3.12 免费激活 Windows 与 Office 快速教程:一条命令去掉未激活水印

MAS v3.12 免费激活 Windows 与 Office 快速教程:一条命令去掉未激活水印 【免费下载链接】Microsoft-Activation-Scripts Open-source Windows and Office activator featuring HWID, Ohook, TSforge, and Online KMS activation methods, along with advanced tro…

2026/10/13 2:16:27 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →