在UniApp项目中,单元测试的基础环境依赖Jest(测试框架)、@vue/test-utils(Vue组件测试工具)、vue-jest(Vue文件转译器)和babel-jest(ES6+语法转译器)。通过以下命令安装:
npm install --save-dev jest @vue/test-utils vue-jest babel-jest
注:若项目使用TypeScript,需额外安装
@babel/preset-typescript和typescript。
在项目根目录创建jest.config.js,配置关键参数以支持Vue单文件组件(SFC)和UniApp API模拟:
module.exports = {
moduleFileExtensions: ['js', 'vue'], // 处理.js和.vue文件
transform: {
'^.+\\.vue$': 'vue-jest', // Vue文件转译
'^.+\\.js$': 'babel-jest' // JS文件转译(需配合babel配置)
},
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1', // 路径别名解析(@指向src)
'uniapp-.*': '<rootDir>/tests/mocks/uniapp.js' // 模拟uniapp API
},
testMatch: ['**/tests/unit/**/*.spec.js'], // 测试文件匹配规则
testEnvironment: 'jsdom', // 模拟浏览器DOM环境(必需)
collectCoverage: true, // 收集测试覆盖率
coverageDirectory: '<rootDir>/tests/unit/coverage' // 覆盖率报告目录
};
注:
moduleNameMapper中的uniapp-.*用于模拟UniApp原生API(如uni.showToast),避免测试时调用真实环境接口。
在tests/mocks/uniapp.js中,通过Jest的jest.fn()模拟常用UniApp API,确保组件测试时API调用可预测:
// 模拟uni.showToast
export const showToast = jest.fn((options) => {
console.log('模拟显示Toast:', options.title);
});
// 模拟uni.request
export const request = jest.fn(() =>
Promise.resolve({ data: { code: 0, message: '请求成功' } })
);
// 导出模拟对象(供组件导入)
export default {
showToast,
request
};
组件中引入UniApp API时,需替换为模拟对象(如import uni from '@/mocks/uniapp'),或在测试用例中通过jest.mock全局模拟。
以Button.vue组件为例(包含点击事件和uni.showToast调用),测试用例需覆盖初始状态、用户交互和API联动:
import { mount } from '@vue/test-utils';
import Button from '@/components/Button.vue';
import uni from '@/mocks/uniapp';
describe('Button.vue', () => {
// 测试初始状态
it('初始按钮文本正确', () => {
const wrapper = mount(Button, {
props: { text: '提交' } // 传递props
});
expect(wrapper.text()).toContain('提交'); // 断言文本内容
});
// 测试点击事件触发API
it('点击按钮调用uni.showToast', async () => {
const wrapper = mount(Button);
await wrapper.find('button').trigger('click'); // 触发点击事件(async等待异步操作)
expect(uni.showToast).toHaveBeenCalledWith({ // 断言API调用参数
title: '点击成功',
icon: 'none'
});
});
// 测试自定义事件触发
it('点击按钮触发自定义事件', async () => {
const wrapper = mount(Button);
await wrapper.find('button').trigger('click');
expect(wrapper.emitted('click')).toBeTruthy(); // 断言自定义事件是否触发
expect(wrapper.emitted('click').length).toBe(1); // 断言事件触发次数
});
});
注:
mount用于完整渲染组件(包括子组件),若需浅渲染(仅测试当前组件),可使用shallowMount;trigger用于模拟用户事件(如点击、输入),emitted用于验证组件发出的自定义事件。
在package.json中添加测试脚本,支持快速执行和CI/CD集成:
{
"scripts": {
"test:unit": "jest", // 运行所有单元测试
"test:unit:watch": "jest --watch", // 监听文件变化实时测试
"test:unit:coverage": "jest --coverage" // 生成覆盖率报告
}
}
执行测试:
npm run test:unit
测试结果会输出到终端,覆盖率报告保存在tests/unit/coverage/lcov-report/index.html(可通过浏览器查看)。
window is not defined(Jest默认无浏览器环境)jest.config.js中添加setupFiles,模拟浏览器API:setupFiles: ['jest-window-mock'] // 安装:npm install --save-dev jest-window-mock
moduleNameMapper中模拟:npm install --save-dev sass-loader sass
moduleNameMapper: {
'\\.(scss|sass)$': 'identity-obj-proxy' // 安装:npm install --save-dev identity-obj-proxy
}
v-if或v-for不渲染mount时传递正确的props或data,例如:const wrapper = mount(Component, {
props: { show: true } // 模拟v-if的条件
});
通过以上步骤,可实现UniApp组件的单元测试,覆盖逻辑验证、交互测试和API联动等场景,提升代码质量和可维护性。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。