单元测试
是前端开发
的关键环节,它能确保代码按预期运行,并在投入生产之前预防错误。无论您是刚入门还是希望提升测试技能,本指南都能帮助您从前端单元测试的初学者晋升到高级水平
。
什么是单元测试?
简单来说,单元测试就是单独测试代码中的每一个小功能,看看它们是否正常工作。就像检查汽车的每个零件一样,确保每个部分都能正常运转。
为什么要进行单元测试?
- ✅ 尽早发现错误 – 在开发阶段就能发现潜在问题
- ✅ 提高代码质量 – 强制我们写出更好的代码结构
- ✅ 使重构更安全 – 重构时有测试保障,不怕破坏现有功能
- ✅ 记录预期行为 – 测试本身就是最好的文档
新手入门:写第一个测试
第一步:选择测试工具
流行的前端测试框架:
Jest
(推荐用于React、Vue、JavaScript
)Mocha + Chai
(灵活但需要更多设置)Vitest
(快速,兼容Vite
)
第二步:安装 Vitest
npm install --save-dev vitest
在 package.json
中添加测试脚本:
{
"scripts": {
"test": "vitest"
}
}
第三步:写你的第一个测试
让我们测试一个简单的加法函数:
sum.js
export const sum = (a, b) => a + b;
sum.test.js
import { expect, test } from "vitest";
import { sum } from "./sum.js";
test("1加2应该等于3", () => {
expect(sum(1, 2)).toBe(3);
});
运行测试:
npm test
恭喜!你刚刚编写了你的第一个单元测试!是不是比想像中简单?
进阶阶段:测试 Vue 组件
第一步:安装 Vue 测试工具
npm install --save-dev @vue/test-utils jsdom
vitest.config.js
配置
import { defineConfig } from "vitest/config";
import vue from "@vitejs/plugin-vue";
export default defineConfig({
plugins: [vue()],
test: {
environment: "jsdom",
globals: true,
},
});
第二步:测试 Vue 组件
Button.vue
<template>
<button @click="onClick"><slot /></button>
</template>
<script setup>
const props = defineProps({ onClick: Function });
const onClick = () => props.onClick && props.onClick();
</script>
Button.test.js
import { describe, it, expect } from "vitest";
import { mount } from "@vue/test-utils"; // 使用 Vue Test Utils 来挂载组件进行测试
import Button from "./Button.vue"; // 引入你的 Vue 组件
describe("Button.vue", () => {
it("点击按钮时,应该触发 click 事件", () => {
const wrapper = mount(Button); // 挂载组件
wrapper.find("button").trigger("click"); // 触发按钮的点击事件
expect(wrapper.emitted("click")).toBeTruthy(); // 检查是否触发了 click 事件
});
it("渲染插槽内容", () => {
const wrapper = mount(Button, {
slots: {
default: "前端开发技术前沿",
},
});
expect(wrapper.text()).toBe("前端开发技术前沿"); // 检查渲染的文本内容
});
});
高级技巧:模拟和异步测试
模拟 API 调用
fetchData.js
export async function fetchData(url) {
const response = await fetch(url);
return response.json();
}
fetchData.test.js
import { vi, expect, test } from "vitest";
import { fetchData } from "./fetchData";
// 模拟 fetch 函数
global.fetch = vi.fn(() =>
Promise.resolve({
json: () => Promise.resolve({ data: "前端开发技术前沿" }),
})
);
test("fetchData 返回模拟数据", async () => {
const data = await fetchData("https://code.ifrontend.net");
expect(data).toEqual({ data: "前端开发技术前沿" });
expect(fetch).toHaveBeenCalledWith("https://code.ifrontend.net");
});
测试组合式函数
useCounter.js
import { ref } from "vue";
export function useCounter(initialValue = 0) {
const count = ref(initialValue);
const increment = () => {
count.value += 1;
};
return { count, increment };
}
useCounter.test.js
import { describe, it, expect } from "vitest";
import { defineComponent, h } from "vue";
import { mount } from "@vue/test-utils";
import { useCounter } from "./useCounter";
describe("useCounter", () => {
it("increment 使计数加一", async () => {
const TestComponent = defineComponent({
setup() {
const { count, increment } = useCounter(0);
return { count, increment };
},
render() {
return h("div", [
h("span", this.count),
h(
"button",
{
onClick: this.increment,
},
"inc"
),
]);
},
});
const wrapper = mount(TestComponent);
await wrapper.find("button").trigger("click");
expect(wrapper.find("span").text()).toBe("1");
});
});

写好单元测试的秘诀
- ✔ 测试功能,不测试实现 – 关注”做什么”,而不是”怎么做”
- ✔ 一个测试只做一件事 – 每个测试只验证一个功能点
- ✔ 起个好名字 – 测试名称要让人一看就知道在测什么
- ✔ 隔离外部依赖 – 让测试不依赖网络、数据库等外部环境
- ✔ 自动化运行 – 在代码提交时自动运行测试
写在最后
单元测试就像给代码买保险,虽然前期需要投入时间,但能让你在后续开发中更加安心。建议从简单的函数开始练习,慢慢扩展到组件测试。记住,好的测试不仅能帮你发现 bug,还能让你的代码质量更上一层楼!
原文链接:https://code.ifrontend.net/archives/1387,转载请注明出处。
评论0