什么是测试驱动开发
TDD 的基本理念是在编写代码之前先编写测试,然后编写足够的代码使测试通过。
这种方式强调通过自动化测试来指导软件开发的过程,以确保开发的代码符合预期的行为和功能。
什么是单元测试
单元测试用于对软件中的最小可测试单位(即单元)进行验证。通常针对代码中的函数、方法或类进行测试。
在单元测试中,开发人员编写测试用例,针对单元的特定输入和预期输出定义断言。然后,这些测试用例由自动化测试框架执行,以验证单元在给定输入时是否产生了预期的输出。
如何编写单元测试
这里我们以一个简单的 isUnDef 函数为例,用来判断入参是不是个 undefined。
const isUndef = x => x === void 0
export default isUndef
安装单元测试框架
TDD 一般都会借助单元测试框架,这里我们使用 Vitest。
npm i vitest -D
等待一杯泡面的时间安装完成后,在项目根目录配置 vitest 的配置文件 vitest.config.js
,这里我们不需要配置:
export default {}
编写测试文件
新建个 js 文件,专门用来存档测试的 case,这样的好处是:
- 同事可以直接读档,看到已经编写的测试内容
- 测试代码和业务解耦分离,互不干扰
- 重构代码时,可以循环利用已写好的测试,编写一次无限测试
import { test, expect } from 'vitest'
import isUndef from './isUndef'
/**
* 第一个参数是测试的注释
* 第二个参数是一个回调函数,具体的测试内容
* expect(x).toBe(y) 代表期望 x 是 y
* expect(x).not.toBe(y) 代表期望 x 不是 y
*/
test('如果参数是 undefined,则返回 true', () => {
const result = isUndef(undefined)
expect(result).toBe(true)
})
// 继续完善测试
test('如果参数是 null,则返回 true', () => {
const result = isUndef(null)
expect(result).toBe(true)
})
test('如果参数是 "yy",则返回 false', () => {
const result = isUndef('yy')
expect(result).toBe(false)
})
执行单元测试
一般会在项目中的 package.json
编写 scripts 执行单元测试,此处直接使用命令行演示:
vitest
或者打开 ui 界面查看测试结果
vitest --ui
以上两种方式都告诉我们单元测试不通过,哪里有 bug,因此我们需要修改 isUndef 函数:
const isUndef = x => x === void 0 || x === null
export default isUndef
再次测试就全部通过了。
VSCode 安装 vitest 插件
如果同事觉得代码写的很猪头,决定用更加短小精悍的宽松相等操作符重构,只需要重构完后直接点击测试即可,不需要再写任何测试,大家共享一个测试体系。
vue 组件测试
这里直接展示下 vite 安装 vitest 中的测试用例:
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import HelloWorld from '../HelloWorld.vue'
describe('HelloWorld', () => {
it('renders properly', () => {
const wrapper = mount(HelloWorld, { props: { msg: 'Hello Vitest' } })
expect(wrapper.text()).toContain('Hello Vitest')
})
})
可以看出上面测试的目的是为了验证传入的 msg 能否正确的被包含在 dom 的 textContent 中。
总结单元测试的好处
- 保证代码确实能够起作用,没有 bug
- 只需要编写一次代码,无限测试
- 所有人共享测试
- 高效试错,直接定位到 bug 出现位置
- 可以将业务拆分为不同的单元测试,通过单元测试来反馈项目开发的进度
- 测试即文档,因为测试的注释说明了代码的功能
- 通过测试进行代码审查