Skip to main content

入门测试驱动开发和单元测试

什么是测试驱动开发

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,这样的好处是:

  1. 同事可以直接读档,看到已经编写的测试内容
  2. 测试代码和业务解耦分离,互不干扰
  3. 重构代码时,可以循环利用已写好的测试,编写一次无限测试
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 中。

总结单元测试的好处

  1. 保证代码确实能够起作用,没有 bug
  2. 只需要编写一次代码,无限测试
  3. 所有人共享测试
  4. 高效试错,直接定位到 bug 出现位置
  5. 可以将业务拆分为不同的单元测试,通过单元测试来反馈项目开发的进度
  6. 测试即文档,因为测试的注释说明了代码的功能
  7. 通过测试进行代码审查