学习目标
- 1理解为什么要写测试
- 2学会为博客功能编写单元测试
- 3掌握TypeScript项目的构建配置
- 4了解部署流程和最佳实践
上一章回顾:代码组织好了,然后呢?
在上一章中,我们学会了用模块系统组织代码——把类型定义、工具函数、业务逻辑分门别类地放好。博客项目现在结构清晰、职责分明。
但有一个问题:
你怎么知道这些代码是正确的?
你可能已经遇到过这种情况:改了一个函数,结果另一个地方坏了。或者上线后用户反馈某个功能不工作了,但你根本不知道是什么时候坏的。
这就是本章要解决的问题——给我们的博客项目加上质量保障。
类比一下:
写代码就像做菜。模块系统帮你把厨房整理好了——调料放这边,食材放那边。但做完菜你得试吃(测试),确认没问题才能端给客人(部署)。如果客人吃了拉肚子(bug),那就是你的测试没做好。
为什么需要测试?
想象一下:你的博客有一个计算阅读时间的功能,逻辑是"每500字1分钟"。
function calculateReadTime(content: string): number {
const words = content.length;
return Math.ceil(words / 500);
}
看起来没问题对吧?但如果有人传了一个空字符串呢?Math.ceil(0 / 500) 返回 0,这倒是合理。但如果传了一个只有10个字的文章呢?Math.ceil(10 / 500) 返回 1,显示"1分钟阅读"——对于10个字的文章来说有点奇怪。
测试的价值:
| 没有测试 | 有测试 | |---------|-------| | 改代码全靠祈祷 | 改代码有底气 | | Bug在用户那里发现 | Bug在开发时就发现 | | 不敢重构 | 随时可以重构 | | 代码本身就是文档 | 测试就是最好的文档 |
测试金字塔:
- 单元测试(我们重点学这个):测试单个函数
- 集成测试:测试多个模块协作
- 端到端测试:测试整个应用流程
第一个测试:为博客工具函数写测试
测试的三个步骤:准备、执行、断言
每个测试都遵循同样的模式,我们叫它 AAA 模式:
it('应该正确更新文章', () => {
// 1. Arrange(准备):设置测试数据
const post = { id: 1, title: '旧标题', content: '内容' };
// 2. Act(执行):调用被测试的函数
const updated = updatePost(post, { title: '新标题' });
// 3. Assert(断言):验证结果
expect(updated.title).toBe('新标题');
expect(updated.content).toBe('内容'); // 其他属性不变
});
类比一下:
AAA就像做实验:
- Arrange = 准备实验器材和材料
- Act = 进行实验操作
- Assert = 观察结果是否符合预期
为博客文章管理写测试
构建配置:让项目可以部署
构建配置:让项目可以部署
测试通过了,接下来要把代码"打包"成可以部署的形式。
tsconfig.json 关键配置:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
配置项说明:
| 配置项 | 作用 | 类比 | |-------|------|------| | target | 编译目标版本 | 翻译成哪种语言 | | outDir | 输出目录 | 成品放在哪里 | | rootDir | 源码目录 | 原材料在哪里 | | strict | 严格模式 | 质检标准高低 |
错误处理:让博客更健壮
常见错误
常见错误
1. 测试太多实现细节
// 不好:测试内部实现
expect(service.posts.length).toBe(1);
// 好:测试行为
expect(service.getPost(1)).toBeDefined();
测试应该关注"做什么"而不是"怎么做"。如果你重构了内部实现但行为不变,测试不应该失败。
2. 忘记测试边界情况
空值、极大值、负数、特殊字符——这些都是容易出bug的地方。
3. 测试之间有依赖
每个测试应该独立运行,不依赖其他测试的状态。用 beforeEach 重置状态。
4. 构建时忘记清理旧文件
# 建议在构建前先清理
rm -rf dist && tsc
部署:让博客上线
代码写好了、测试通过了、构建完成了——接下来就是部署。
部署流程:
- 代码检查:确保没有TypeScript错误
- 运行测试:确保所有测试通过
- 构建项目:生成可部署的文件
- 上传部署:推送到服务器或平台
常用部署平台:
| 平台 | 特点 | 适合场景 | |-----|------|---------| | Vercel | Next.js官方,一键部署 | 个人博客、小项目 | | Netlify | 免费额度大 | 静态站点 | | 自己的服务器 | 完全控制 | 企业项目 |
package.json 脚本配置:
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"test": "jest",
"lint": "eslint src --ext .ts,.tsx",
"typecheck": "tsc --noEmit"
}
}
动手实践
现在轮到你了!让我们为博客项目添加测试和部署配置。
练习1:为格式化函数写测试
创建一个 formatDate 函数,然后为它写测试:
- 输入 Date 对象,返回 "YYYY-MM-DD" 格式
- 处理空值情况
练习2:为文章验证写测试
创建一个 validatePost 函数:
- 标题不能为空
- 标题长度不超过100
- 内容不能为空
- 返回验证结果(成功或错误信息)
练习3:配置构建脚本
为你的项目配置完整的 package.json 脚本,包括:类型检查、测试、构建。
本章总结
恭喜你!你已经学会了如何保障代码质量:
本章要点:
- 测试是代码质量的保障,不是可有可无的
- AAA模式(准备-执行-断言)是写测试的基本框架
- 测试应该关注行为,而不是实现细节
- 边界情况是最容易出bug的地方
- 构建配置让项目可以部署到生产环境
对比一下:
| 学习前 | 学习后 | |-------|-------| | 改代码靠祈祷 | 改代码有测试保障 | | 不知道代码有没有bug | 测试告诉你哪里有bug | | 代码只能在本地跑 | 代码可以部署上线 |
下一章预告:
在下一章中,我们将进入TypeScript的高级类型世界——联合类型、交叉类型、类型守卫。这些工具会让你的类型定义更灵活、更强大。
就像学会了基础武功,现在要开始学进阶招式了!
交互式练习
测试练习:为计算函数写测试
为博客的阅读时间计算函数编写完整的单元测试
章节测验
测试的AAA模式指的是什么?