首页/新闻资讯/正文详情

从 TDD 到自动化测试:改善 GitHub 开源项目代码质量的完整实践

发布时间:2026/9/23 22:47:56 来源:云帆数科 栏目:资讯中心
从 TDD 到自动化测试:改善 GitHub 开源项目代码质量的完整实践
从 TDD 到自动化测试改善 GitHub 开源项目代码质量的完整实践【免费下载链接】githubGitHub 漫游指南- a Chinese ebook on how to build a good project on Github. Explore the users behavior. Find some thing interest.项目地址: https://gitcode.com/phodal/github本文以《GitHub 漫游指南》改善 GitHub 项目代码质量测试一章chapters/07-tdd-with-autotest.md为核心骨架完整讲解在开源项目开发中落地测试驱动开发TDD、用 Twill 做轻量级功能测试、用 sinon Fake Server 隔离前端网络依赖以及如何把测试接入 GitHub 项目日常开发流程。读完你将掌握什么场景下 TDD 真正有价值、如何一步步写出并运行一个可重复执行的网站功能测试脚本以及如何在无真实后端的情况下测试前端数据交互。为什么开源项目必须补上测试这一课在 GitHub 上维护一个开源项目代码会被别人阅读、fork、复用测试就不再是可有可无的收尾工作而是项目质量与协作的基础设施。在本书第一章关于如何用好 GitHub的讨论中作者曾这样总结自己写测试的动机不希望每次做完一个新功能时都手动地把旧功能再测一遍——需要自动化测试不希望在重构时破坏了原有功能还一无所知不敢 push 代码因为对改动没有把握。而在长期维护 GitHub 项目的实践中作者进一步把测试提到了最后一公里的高度测试是代码的最后一公里。所以尽可能为你的 GitHub 上的项目添加测试。甚至可以说没有测试重构就是空中楼阁详见重构一章对不要轻易尝试没有测试的重构的告诫。本章给出的路线图非常清晰先是TDD测试驱动开发建立测试先行的思维方式再用Twill这类轻量级工具做网站功能测试最后用sinon Fake Server隔离前端对网络的依赖。三者恰好覆盖了单元级—功能级—前端交互级三个测试层次。TDD让测试先行在开源项目中真正落地一次测试驱动开发物联网服务端授权功能的实战TDD 说得再多不如一次真实开发过程来得直观。作者在重写一个物联网服务端项目Lan时任务聚焦于结合 CoAP、MQTT、HTTP 等协议的云服务的协议与授权部分——不同协议下的授权机制各不相同这正是一个我知道要什么但暂时不清楚每一种协议深层次怎么工作的场景。HTTP 协议的授权最简单先用 curl 直接验证curl --user root:root -X PUT -d { dream: 1 } -H Content-Type: application/json http://localhost:8899/topics/test因为我们对 HTTP 协议足够熟悉只要在请求中判断有没有req.headers.authorization即可if (!req.headers.authorization) { res.statusCode 401; res.setHeader(WWW-Authenticate, Basic realmSecure Area); return res.end(Unauthorized); }MQTT 协议也算友好因为协议本身自带用户名/密码授权用mosquitto_pub一条命令就能完成验证mosquitto_pub -u root -P root -h localhost -d -t lettuce -m Hello, MQTT. This is my first message.CoAP 协议则没有那么方便——它没有内建的用户名密码机制授权是通过 Option选项字段来传递的。当时已有的工具如 libcoap 只能提供非常基础的能力coap-client -m get coap://127.0.0.1:5683/topics/zero -T于是作者先写了一个 Node.js 测试脚本来验证 CoAP 授权功能var coap require(coap); var request coap.request; var req request({hostname: localhost,port:5683,pathname: ,method: POST}); ... req.setHeader(Accept, application/json); req.setOption(Block2, [new Buffer(phodal), new Buffer(phodal)]); ... req.end();写完之后作者突然意识到这不就是测试代码吗既然要写的测试脚本已经存在为什么不把它放进 spec测试目录让整个实现过程变成真正的 TDD于是一次先写验证脚本、后补功能的实践自然地演变成了一次完整的测试驱动开发。说说 TDD四个基本步骤测试驱动开发是一个很古老的开发方法但因为国内常见的开发人员负责功能、由他人或事后补测试流程这套方法论并没有被广泛实践。它的核心流程只有四步先写功能的测试先描述这个功能应该表现出什么行为实现功能代码写刚好能让测试通过的最小实现提交代码commit → 保证功能正常在功能通过测试后立刻提交让提交历史与功能正常绑定重构功能代码在不改变行为的前提下改善代码结构测试继续作为安全网。对于物联网服务端这个项目作者已经具备了开展 TDD 的两个有利前提已经有了原型协议的行为可以被探知、框架设计已经完成知道代码该放在哪里。TDD 思考它到底什么时候有价值作者对自己的实践做了很坦诚的反思区分了两种截然不同的情况当 TDD 可有可无时如果我已经知道要实现的大部分功能、也知道如何实现同时对 Code Smell代码坏味道保持警惕、保证功能被测试覆盖那么 TDD 带来的增量价值并不大——此时先写测试更像是一种仪式而非必需。当 TDD 很有价值时当我知道想要的功能但并不理解其深层次的机制需要花大量时间去弄明白它为什么是这样、需要先写一些脚本来确认它是怎么工作的时TDD 的价值就凸显出来了——测试驱动出的不只是代码更是对未知领域的探索。而且完成测试脚本之后你会发现这些脚本本身已经成了代码的一部分。结论很直接在这种情况下我们为什么不 TDD 呢 在后面章节回顾这段经历时作者也补充了一个关键视角从测试开始的 TDD会保证方法是可测的而先写功能再补测试往往只让测试成为测试而不是代码的一部分。功能测试用 Twill 做轻量级网站测试Twill 是什么twill was initially designed for testing Web sites, although since then people have also figured out that its good for browsing unsuspecting Web sites.Twill 最初被设计用来测试网站后来人们发现它也适合浏览那些不设防的网站。作者称其轻量是因为它有三个特点直接在命令行上操作无需编写完整测试框架代码内置了一套DSL领域特定语言测试脚本可读性极强它是一个Python 库可以方便地与 Python 脚本结合。除了常规的功能测试它还能用来做一种过程化的压力测试模拟完整用户流程比如同时有多少人登录你的网站。不过它有一个明确限制——不支持 JavaScript因此只适用于不依赖 JS 渲染的页面场景。从源码结构看仓库文档对 Twill 原理的说明它的工作机制大致是用 Python 的requests库下载 HTML再用lxml解析 HTML并内嵌一套 DSL 来驱动打开页面—查看表单—填充—提交的完整流程。安装方式非常简单pip install twillTwill 登录测试完整实操下面以测试一个 Web 应用的登录功能为例逐步走一遍完整的交互式测试1. 启动应用先让被测服务在本地运行起来。2. 进入 twill shelltwill-sh - Welcome to twill! - current page: *empty page*3. 打开网页 go http://127.0.0.1:5000/login at http://127.0.0.1:5000/login current page: http://127.0.0.1:5000/login4. 显示页面上的表单 showforms Form #1 ## ## __Name__________________ __Type___ __ID________ __Value__________________ 1 csrf_token hidden csrf_token 1423387196##5005bdf3496e09b8e2fbf450 ... 2 email email email None 3 password password password None 4 login submit (None) 登入 current page: http://127.0.0.1:5000/login可以看到表单里有四个字段csrf_tokenCSRF 防护的隐藏字段值由服务端生成、email、password以及一个值为登入的login提交按钮。5. 清空并填充表单formclear 1 fv 1 email testtes.com fv 1 password test其中formclear 1表示清空编号为 1 的表单fv 1 email ...表示给表单 1 的email字段赋值。6. 修改表单的提交地址actionformaction 1 http://127.0.0.1:5000/login7. 提交表单 submit Note: submit is using submit button: namelogin, value登入 current page: http://127.0.0.1:5000/提交后页面跳转到了http://127.0.0.1:5000/首页说明登录成功后发生了重定向——功能按预期工作。Twill 测试脚本把交互固化成可重复执行的测试交互式 shell 适合探索但真正要测试就必须把步骤固化成脚本。把上面的操作写入login.twillgo http://127.0.0.1:5000/login showforms formclear 1 fv 1 email testtes.com fv 1 password test formaction 1 http://127.0.0.1:5000/login submit go http://127.0.0.1:5000/logout运行脚本注意与交互模式相同使用twill-sh直接执行文件twill-sh login.twill执行结果会逐步回放每一步命令及对应输出 EXECUTING FILE login.twill AT LINE: login.twill:0 at http://127.0.0.1:5000/login AT LINE: login.twill:2 Form #1 ## ## __Name__________________ __Type___ __ID________ __Value__________________ 1 csrf_token hidden csrf_token 1423387345##7a000b612fef39aceab5ca54 ... 2 email email email None 3 password password password None 4 login submit (None) 登入 AT LINE: login.twill:3 AT LINE: login.twill:4 AT LINE: login.twill:5 AT LINE: login.twill:6 Setting action for form (Element form at 0x10e7cbb50,) to (http://127.0.0.1:5000/login,) AT LINE: login.twill:7 Note: submit is using submit button: namelogin, value登入 AT LINE: login.twill:9 at http://127.0.0.1:5000/login -- 1 of 1 files SUCCEEDED.注意两处关键信息执行日志中AT LINE: login.twill:N会逐行标注当前执行到脚本的哪一行最后的1 of 1 files SUCCEEDED.表示所有脚本文件全部执行成功——一个成功的功能测试就这样诞生了。脚本最后访问/logout退出登录保证每次执行都从干净的会话状态开始测试可重复运行。Fake Server用 sinon 在前端测试中隔离网络依赖单测的原则之一是把被测代码与外部依赖隔离开。前端代码中的fetch/ Ajax 请求就是一个典型的依赖真实环境下我们无法控制服务端返回什么。sinon 的fakeServer可以拦截请求并返回我们预设的假响应从而在无真实后端的情况下完成测试。用 fakeServer 预设接口响应sinon 框架的fakeServer.create()会创建一个假的 XHR 服务器拦截当前环境中的所有 Ajax/fetch 请求。在beforeEach中创建 server 并预设响应var data {id:1,name:Rice,type:Good,price:12,quantity:1,description:Made in China}; beforeEach(function() { this.server sinon.fakeServer.create(); this.rices new Rices(); this.server.respondWith( GET, http://localhost:8080/all/rice, [ 200, {Content-Type: application/json}, JSON.stringify(data) ] ); });respondWith的三个参数依次是请求方法GET、请求 URL、以及响应三元组[状态码, 响应头, 响应体]。这里我们预设了http://localhost:8080/all/rice这个 GET 接口返回 200 状态码和 JSON 格式的data。在afterEach中必须恢复restore这个 server否则它会在测试结束后继续拦截后续请求污染其他用例afterEach(function() { this.server.restore(); });配合 Jasmine 编写完整测试用例预设好响应之后用 Jasmine 写断言。测试逻辑是触发this.rices.fetch()发起请求 → 调用this.server.respond()让 fakeServer 立即响应→ 校验拿到的数据是否与预设一致describe(Collection Test, function() { it(should get data from the url, function() { this.rices.fetch(); this.server.respond(); var result JSON.parse(JSON.stringify(this.rices.models[0])); expect(result[id]) .toEqual(1); expect(result[price]) .toEqual(12); expect(result) .toEqual(data); }); });这个用例验证了三层信息单个字段的值id等于 1、price等于 12、以及整个解析结果与预设数据完全一致。this.server.respond()是关键——它让被拦截的请求立即以预设响应返回从而把网络往返从测试中彻底移除。这种模式在本书前面章节介绍的 Lettuce 项目测试中也能看到影子利用jasmine.Ajax拦截请求、用respondWith伪造响应从而只测代码逻辑、不依赖真实网络。把测试接入 GitHub 项目的日常流程测试写好之后关键的一步是让它跑起来且持续地跑——否则测试文件只会躺在仓库里慢慢腐烂。在构建 GitHub 项目的自动化测试章节中本书给出了一个完整的接入方案第一步在package.json里注册测试脚本。scripts: { test: mocha }第二步配置 Mocha 的mocha.opts。--reporter spec --ui bdd --growl --colors test/spec其中--reporter spec指定输出格式--ui bdd启用 BDD 风格的describe/it语法与上面 sinon Jasmine 的用例风格一致--growl开启系统通知最后一行test/spec指定测试文件所在目录。第三步接入 CI。该章节给出了一个 Travis CI 配置示例.travis.yml核心是声明语言环境与分支language: node_js node_js: - 0.10 notifications: email: false branches: only: - gh-pages这样做的收益是每次 push 代码时 CI 自动执行全部测试一旦有测试失败提交者会立刻收到反馈——这正是测试是代码的最后一公里的工程化落地。此时再回头看 TDD 的第三步提交代码commit → 保证功能正常在 CI 的配合下提交时功能正常从一个主观承诺变成了一个可验证的事实。小结从本章可以看到一套完整的开源项目测试思路TDD 的取舍TDD 不是银弹。当已知且可预测时它价值有限当目标明确但机制未知如物联网多协议授权时它是探索和驱动开发的最佳工具。而无论哪种情况从测试开始都会保证代码可测。功能测试要轻Twill 用命令行 DSL 解决了网站功能是否正常的问题几分钟就能从零写出可重复执行的login.twill脚本让登录成功这类行为有了机器可验证的答案。前端测试要隔离sinonfakeServerrespondWith Jasmine 的组合让前端代码在完全脱离真实网络的情况下完成可靠的单测配合afterEach的restore()保证用例互不污染。测试要持续运行通过package.json的test脚本与 CI 配置让每一次 push 都自动执行全部测试把功能正常固化为可持续验证的工程事实。这套方法论在 GitHub 上维护项目时尤其重要——你的代码会被他人阅读与贡献而一个带有完善测试的开源项目既是对贡献者的信任背书也是让项目能够长期健康演进的前提。【免费下载链接】githubGitHub 漫游指南- a Chinese ebook on how to build a good project on Github. Explore the users behavior. Find some thing interest.项目地址: https://gitcode.com/phodal/github创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

C++ WebSocket源码包落地指南:从依赖识别到编译运行
C++ WebSocket源码包落地指南:从依赖识别到编译运行

简介:这是基于C与原生socket实现的WebSocket服务器源码包,面向有一定C网络编程基础、需要自行搭建或理解WebSocket协议的开发者。程序中实现了协议握手、基于帧格式的数据解码与传输,并附有在线测试网页的使用说明,便于验证服务器… · 2026/9/23 22:47:56

DeepSeek R1本地部署+知识库搭建实战:从Ollama到RAG全指南
DeepSeek R1本地部署+知识库搭建实战:从Ollama到RAG全指南

简介:不少大模型爱好者正在寻找DeepSeek R1本地离线部署与私有知识库搭建的完整方案。这份PDF教程定位非常清晰,面向具备基础计算机操作能力的开发者和普通用户,完整演示了从安装Ollama、拉取合适的DeepSeek R1模型,到通过Cherry-… · 2026/9/23 22:47:56

电塔鸟巢检测双格式数据集:VOC与YOLO目标检测实战解析
电塔鸟巢检测双格式数据集:VOC与YOLO目标检测实战解析

简介:面向电塔巡检与生态研究场景,这份鸟巢目标检测数据集以1165张jpg图片为基础,标注类别为单一“nest”,共含1187个鸟巢矩形框,可直接用于智慧电网安全预警、鸟类栖息监测以及目标检测模型训练等任务。数据同时提供P… · 2026/9/23 22:47:50

中文法律大模型微调实战:从词表扩展到LoRA训练全流程
中文法律大模型微调实战:从词表扩展到LoRA训练全流程

简介:这份资源面向希望将大语言模型落地到中文法律场景的开发者与算法学习者,围绕法律问答、法条理解与指令微调等任务,提供了一套可复现的工程实践材料。包内共42个文件,以Python脚本、JSON配置与数据、Shell运行脚本为主&#x… · 2026/9/23 23:24:05

wired-elements 版本演进全解:从 1.0 到 3.0 的手绘风 Web Components 技术脉络
wired-elements 版本演进全解:从 1.0 到 3.0 的手绘风 Web Components 技术脉络

UI组件前端 【免费下载链接】wired-elements Collection of custom elements that appear hand drawn. Great for wireframes or a fun look. 项目地址: https://gitcode.com/gh_mirrors/wi/wired-elements 点击查看 免费下载 导读 wired-elements 是一个以"… · 2026/9/23 23:24:05

纺锤线与风高浪大线:从形态到实战的K线分歧信号识别
纺锤线与风高浪大线:从形态到实战的K线分歧信号识别

做股票交易的人,几乎都会在某一刻盯着一根K线发呆——实体小到几乎看不见,上下影线却长得像天线,多空双方激烈交手一整天,收盘价却回到开盘价附近。这根线,老交易员叫它纺锤线;如果当天振幅再大一些&#x… · 2026/9/23 23:24:05

AWS SaaS 架构实战:多租户模型选型与租户隔离落地指南
AWS SaaS 架构实战:多租户模型选型与租户隔离落地指南

简介:这份PPT资料面向正在或计划将传统软件转型为SaaS模式的独立软件供应商架构师、技术负责人与云计算从业者,系统梳理了基于AWS构建SaaS平台的整体架构思路与关键技术选型。内容围绕身份管理、多租户隔离、应用分层隔离、管理监控、测量计费、业务敏捷… · 2026/9/23 23:23:59

SAP TM运输模块详解:从架构配置到费用结算的实践指南
SAP TM运输模块详解:从架构配置到费用结算的实践指南

简介:SAP-TM运输模块详解是一份面向SAP实施顾问、SD/物流模块顾问及后勤执行环节业务人员的PDF手册。文档围绕TM作为SD子模块的定位,系统拆解了自动计算交货成本的两大核心任务:创建运输单与计算交货成本,并覆盖从后台配置到前台操… · 2026/9/23 23:23:59

mRemoteNG 端口扫描(Port Scan)完全指南:网段探测、协议识别与批量导入连接
mRemoteNG 端口扫描(Port Scan)完全指南:网段探测、协议识别与批量导入连接

桌面应用网络 【免费下载链接】mRemoteNG mRemoteNG is the next generation of mRemote, open source, tabbed, multi-protocol, remote connections manager. 项目地址: https://gitcode.com/gh_mirrors/mr/mRemoteNG 点击查看 免费下载 mRemoteNG 内置的 Port S… · 2026/9/23 23:23:52

3招搞定手机怎么下载微信面试难题实战项目解析
3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧
Win7无线热点配置工具源码解析:解决API失效的3个实战技巧

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧 Win7无线热点配置工具在Win10/11上跑不动?不是你的问题,是版本升级后 API 全变了。很多老项目里的 netsh wlan… · 2026/9/23 0:00:36

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码