
开发工具后端【免费下载链接】shieldsConcise, consistent, and legible badges in SVG and raster format项目地址https://gitcode.com/gh_mirrors/sh/shields点击查看免费下载本篇指南面向所有在 Shields 项目中新增徽章服务或修改现有徽章行为的开发者。文章以 doc/service-tests.md 为骨架结合 core/service-test-runner/ 下的测试框架源码与 services/docsrs/ 的真实案例系统讲解如何为徽章编写自动化服务测试、如何运行与调试、如何用 Nock 拦截响应以及如何生成覆盖率报告。读完你将从零写出可被 CI 与代码评审认可的服务测试套件。为什么要为徽章编写服务测试在 Shields 中为新增服务或修改行为编写自动化测试承担着三重职责验证实现正确性贡献者与评审者可以快速确认代码按预期工作监控上游 API 变化当一个徽章因上游 API 变更而停止工作时维护者能第一时间发现降低后续贡献成本未来的贡献者在调试或改进徽章时可以直接借助测试快速定位问题。一份合格的服务测试应覆盖以下四类场景正常valid行为可选参数如 tags、branches、version 等自定义的错误处理逻辑若服务定义了非平凡的校验器validator还需包含对畸形响应malformed responses的测试。服务测试的工程基础ServiceTester 与 IcedFrisbyShields 的服务测试建立在IcedFrisby一个 API 测试框架之上并封装了一层服务于徽章场景的抽象。核心类与文件如下core/service-test-runner/create-service-tester.js约定式地根据.tester.js文件自动创建ServiceTester实例core/service-test-runner/service-tester.js封装一组测试的ServiceTester类core/service-test-runner/icedfrisby-shields.js对 IcedFrisby icedfrisby-nock 的二次封装提供expectBadge()、expectRedirect()等徽章专用断言core/service-test-runner/runner.js加载所有 tester 并按需筛选注册到 Mochacore/service-test-runner/cli.js命令行入口负责解析参数、启动本地测试服务器并调用 Runner。createServiceTester()的实现依赖 Node 的caller模块推断调用文件路径当从docsrs.tester.js调用时它会将文件名中的.tester.js替换为.service.js动态导入该服务模块并取出默认导出的服务类最后调用ServiceTester.forServiceClass()完成构造见 create-service-tester.js。从源码可以看到两点约束它要求.service.js模块默认导出单一服务类且必须是 core/base-service/base.js 的子类否则会抛出does not export a single service错误并提示直接使用new ServiceTester()ServiceTester.forServiceClass()会取服务类route.base如docsrs作为pathPrefix见 service-tester.js这正是测试请求无需写完整前缀/docsrs的原因。toss()方法负责把测试注册到 Mocha它会把pathPrefix拼接到 base URL 之后作为每个测试的baseUri并根据测试是否使用了intercept()自动为测试名加上[live]或[mocked]标记见 service-tester.js。实战教程以 Docs.rs 徽章为例我们以 services/docsrs/docsrs.service.js 为例这个服务展示 Rust 包crate的文档构建状态。动手前请先按 doc/TUTORIAL.md 中的 Setup 章节搭建好开发环境。(1) 搭建测试脚手架徽章代码位于services/docsrs/docsrs.service.js测试文件应与之配套存放于services/docsrs/docsrs.tester.js。在测试文件中写入如下样板import { createServiceTester } from ../tester.js export const t await createServiceTester()createServiceTester从 services/tester.js 导出该文件同时导出了底层的ServiceTester类供需要手工构造的场景使用。由于我们的.service.js默认导出单个类createServiceTester会按约定自动创建一个针对docsrs.service.js的ServiceTester对象后续所有测试都挂载到导出的t上。(2) 编写第一个测试用例先为最典型的场景不带 version 参数添加测试import Joi from joi t.create(Docs with no version specified) .get(/tokio.json) .expectBadge({ label: docs, message: Joi.equal(passing, failing), })这里有几点关键设计create()之后链式调用的方法来自 IcedFrisbyget()用于发起对徽章 URL 的请求测试会真实访问外部服务而不 mock这与单元测试的惯例不同但正是服务测试的目的所在——当上游 API 发生破坏性变更时能立刻报警。因此至少应保留一个直接调用真实 API 的测试为什么请求.json格式Shields 上所有徽章都支持多种格式除https://img.shields.io/docsrs/tokio.svgSVG 图片外还可以请求https://img.shields.io/docsrs/tokio.json获得 JSON 格式。测试用 JSON 格式便于对内容做断言URL 前缀自动补全createServiceTester()会读取服务类route.base此处为/docsrs作为请求的 base URL所以测试中只需写/tokio.json而不是/docsrs/tokio.json。从 docsrs.service.js 可以看到static route { base: docsrs, pattern: :crate/:version? }expectBadge()的断言能力其label、message、color等字段既可以是字符串字面量也可以是RegExp或Joischema。底层实现位于 icedfrisby-shields.js字符串/数字做严格相等断言正则用Joi.string().regex()校验Joi schema 则直接交给Joi.attempt()其他类型会抛出明确的类型错误同时它只接受label、message、logoWidth、labelColor、color、link这几个白名单字段图片检查picture check思想依赖真实服务的测试不应断言某个具体构建状态而应断言徽章数据符合预期模式。这里用Joi.equal(passing, failing)列出所有合法取值既能在徽章生成抛错或上游 API 有破坏性变更时让测试失败又不会因示例 crate 的构建状态变化而误报。对于更复杂的场景services/test-validators.js 预置了大量可直接复用的 Joi 验证器isVPlusDottedVersionAtLeastOne版本号、isMetric1k、2.5M这类指标、isCommitHash、isStarRating、isPercentage、isDefaultTestTotals等version、downloads、rank 等常见徽章类型大多已有现成验证器。另外需要说明编写 IcedFrisby 测试时通常要调用toss()来注册测试但在 Shields 中不需要——测试框架会自动调用见 runner.js 与 service-tester.js。(3) 运行测试运行刚写好的测试npm run test:services -- --onlydocsrs--only指定要测试的服务可传逗号分隔的服务名列表额外的--让 NPM CLI 把后面的参数原样透传给测试运行器。预期输出大致如下Server is starting up: http://localhost:1111/ DocsRs [live] Docs with no version specified √ [ GET /tokio.json ] (441ms) 1 passing (1s)输出里的[live]标记说明这是一个直连外部服务的测试Server is starting up: http://localhost:1111/表明测试框架自动在 1111 端口启动了本地测试服务器见 cli.js。当测试失败时可以开启调试日志帮助定位npm run test:services:trace -- --onlydocsrs这条命令会输出额外的请求/响应跟踪信息。(4) 覆盖更多路径可选参数与自定义错误Docs.rs 徽章支持可选的 version 参数pattern: :crate/:version?默认latest见 docsrs.service.js。针对确定构建成功的历史版本可以用字符串字面量收窄期望失败时能得到更明确的错误信息t.create(Passing docs for version).get(/tokio/1.37.0.json).expectBadge({ label: docs1.37.0, message: passing, color: brightgreen, })注意这里显式断言了color只有当徽章实现了自定义配色逻辑时才需要显式测试颜色。在 docsrs.service.js 的render()方法中passing对应success色、failing对应critical色因此颜色断言在这里是有意义的。运行结果Server is starting up: http://localhost:1111/ DocsRs [live] Docs with no version specified √ [ GET /tokio.json ] (408ms) [live] Passing docs for version √ [ GET /tokio/1.37.0.json ] (171ms) 2 passing (2s)测试多了以后可以用--fgrep只跑其中一条npm run test:services -- --onlydocsrs --fgrepPassing docs for version由于 tokio 1.32.1 的文档构建是失败的可以补一个失败场景的测试t.create(Failing docs for version).get(/tokio/1.32.1.json).expectBadge({ label: docs1.32.1, message: failing, color: red, })接下来覆盖错误路径。Docs.rs 集成在带 version 时定义了 400 状态码的自定义错误见 docsrs.service.jshttpErrors: version ? { 400: malformed version } : {},先测试 crate 与 version 均不存在404的场景t.create(Crate not found) .get(/not-a-crate/latest.json) .expectBadge({ label: docs, message: not found }) t.create(Version not found) .get(/tokio/0.8.json) .expectBadge({ label: docs, message: not found })再测试畸形 version 触发自定义错误映射的场景t.create(Malformed version) .get(/tokio/not-a-version.json) .expectBadge({ label: docs, message: malformed version })以上所有用例都已经实际落在仓库的 services/docsrs/docsrs.tester.js 中该文件还额外包含Multiple builds, latest passing针对bevy_tweening多构建场景与Getting latest version works针对/rand/latest.json两个用例可作为完整测试套件的参考范本。Mocking 响应用 Nock 拦截上游请求如果找不到“构建失败的稳定示例版本”另一种思路是 mock 响应。以Failing docs for version为例可以改写为t.create(Failing docs for version) .get(/tokio/1.32.1.json) .intercept(nock nock(https://docs.rs/crate) .get(/tokio/1.32.1/status.json) .reply(200, { doc_status: false }), ) .expectBadge({ label: docs1.32.1, message: failing, color: red, })intercept()来自 icedfrisby-nock 插件它接收一个 setup 函数并返回 Nock 拦截器从而暴露 Nock 的完整 API。结合 icedfrisby-shields.js 的源码可知调用intercept()会同时关闭网络networkOff()并把该测试标记为intercepted因此运行输出中会显示[mocked]标记反之使用get()的测试保持networkOn()显示[live]。Nock 非常挑剔HTTP 方法GET、协议https、host 与路径必须完全匹配mock 才会生效。这里 mock 的 URL 与 docsrs.service.js 中fetch()请求的https://docs.rs/crate/${crate}/${version}/status.json一一对应。在 CI 或对稳定性敏感的场合cli.js 还支持用SKIP_INTERCEPTEDtrue跳过所有拦截型测试见 cli.js。更精细的测试运行控制core/service-test-runner/cli.js 顶部注释列出了测试运行器的全部能力除了前面用到的--only之外还包括从 stdin 读取服务列表换行分隔echo service1\nservice2\nservice3 | npm run test:services -- --stdin--stdin与--only不能同时使用CLI 会打印错误并忽略指定被测实例SKIP_INTERCEPTEDtrue TESTED_SERVER_URLhttps://test.shields.io npm run test:services --当设置了TESTED_SERVER_URL时测试直接打到该地址不再自动启动 1111 端口的本地服务器失败重试用于应对偶发的不稳定测试RETRY_COUNT3 RETRY_BACKOFF100 npm run test:services --RETRY_BACKOFF单位是毫秒对应 IcedFrisbyretry(count, backoff)参数。另外Runner 的only(services)方法按服务名前缀不区分大小写匹配 tester并会在没有匹配到任何服务时抛出Unknown services: ...错误见 runner.js。本地运行时测试服务器会在每个用例前调用server.reset()清空请求缓存避免用例间互相污染见 cli.js。代码覆盖率确认没有遗漏分支通过覆盖率报告可以确认测试是否覆盖了所有代码路径npm run coverage:test:services -- -- --onlydocsrs npm run coverage:report:open第一条命令基于服务测试生成覆盖率数据第二条命令在浏览器中打开覆盖率报告。结合覆盖率报告检查render()、fetch()与错误分支是否都有对应的测试用例是提高测试质量的常用手段。Pull Requests 中的测试约定PR 必须遵循 CONTRIBUTING.md 中记录的约定才能执行正确的服务测试集合。Shields 的 CI 运行机制如下见 cli.js定时构建运行全部服务测试Pull Request仅运行 PR 标题中指定的服务测试例如标题[Travis] Fix timeout issues会运行 Travis 相关测试[CRAN CPAN CTAN] Add test coverage会运行 CRAN、CPAN、CTAN 三个服务。该机制由test:services:pr脚本分两步完成先用 core/service-test-runner/pull-request-services-cli.js 解析 PR 标题中的服务名列表通过 services-for-title.js 实现再读取该列表运行对应测试。之所以拆成两个独立进程是因为生成服务列表是异步操作而 Mocha 的describe.only等独占测试只能同步应用分步执行既规避了这一限制也更便于在开发机上调试。小结与进一步阅读服务测试是 Shields 徽章质量的守门员它既验证贡献者的实现也在上游 API 变动时第一时间发出警报并为后来者留下可直接运行的行为契约。写作时遵循真实调用 必要 mock 错误路径 畸形输入的组合配合--only、--fgrep、SKIP_INTERCEPTED、重试参数与覆盖率报告即可高效、稳健地完成测试开发与维护。若对测试编写有疑问可以在仓库中打开 issue如果目标徽章已有相关 issue直接在对应 issue 下评论即可。如需深入可继续阅读core/service-test-runner/service-tester.jsServiceTester 完整实现含pathPrefix拼接与toss()注册逻辑core/service-test-runner/icedfrisby-shields.jsexpectBadge()断言字段白名单与类型分发逻辑services/test-validators.js共享 Joi 验证器集合services/docsrs/docsrs.tester.js本篇教程对应的完整测试文件含多构建、最新版本等额外用例IcedFrisby、Joi、icedfrisby-nock 与 Nock 的官方 API 文档。赞分享开发工具后端【免费下载链接】shieldsConcise, consistent, and legible badges in SVG and raster format项目地址https://gitcode.com/gh_mirrors/sh/shields点击查看免费下载相关推荐ESP8266 Deauther隐藏的1.5MB OUI数据库MAC地址厂商识别原理与更新方法ESP8266 Deauther隐藏的1.5MB OUI数据库MAC地址厂商识别原理与更新方法 ESP8266 Deauther 是一款基于廉价 ESP826嵌入式物联网网络安全渗透测试react-jsonschema-form与Jest测试覆盖率报告徽章react jsonschema form与Jest测试覆盖率报告徽章 你是否在开发表单应用时遇到过测试覆盖不全的问题是否想过如何直观展示项目的测试质量本文前端UI组件flexivit_base.300ep_in21k vs 传统ViT19.4 GMACs如何实现更优性能flexivit_base.300ep_in21k vs 传统ViT19.4 GMACs如何实现更优性能 在计算机视觉领域视觉TransformerVi上一篇PHPExcel终极指南完整社区资源汇总与第三方工具大全 下一篇终极Veil安全指南10个专业技巧教你在渗透测试中正确使用载荷生成工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考