前端单元测试

本文探讨了前端开发中的两种测试类型——unit测试和E2E测试,并着重阐述了在Vue项目中进行单元测试的原因及步骤。通过安装Jest,配置Babel,结合Vue Test Utils,可以编写测试用例来确保组件的正确性,如表单校验等。单元测试增强了代码健壮性,降低了测试人员的压力,提高了测试效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

测试类型

unit测试

  1. 主要对组件进行测试。
  2. 数据的有效性测试
  3. 关注组件本身。

vue 单元测试的范围仅限于数据流动是否正确,逻辑渲染是否正确(v-if v-show v-for),style 和 class 是否正确,我们并不需要关系这个组件在浏览器渲染中的位置,也不需要关系对其它组件会造成什么影响,只要保证组件本身正确即可。如表单校验、计算金额等校验等。

E2E 测试

  1. 测试真实DOM是否满足预期。
  2. 测试业务流程
  3. 变手动点点点为自动化处理

单元测试原因

  1. 增强代码健壮性 增删改代码后保证不影响原先功能
  2. 降低测试人员压力 提高测试效率
  3. 提高逼格

vue项目中进行单元测试

安装环境

  1. 安装 Jest
$ npm install --save-dev jest @vue/test-utils
  1. 处理单文件组件
npm install --save-dev vue-jest
  1. 配置 Babel
npm install --save-dev babel-jest

具体参考Vue Test Utils选择一个测试运行器

编写测试用例

如下是一个表单的校验测试

import { mount, createLocalVue } from '@vue/test-utils'
import iview from 'iview'
import AddForm from '@/pages/config-manager/customer-complain-config/finish-rule-config/finish-rule/components/AddEditModal.vue'
import flushPromises from 'flush-promises'

const localVue = createLocalVue()
localVue.use(iview)
const selectArr = { "productChildTypeList": [{ "productTypeId": 8, "productTypeName": "门锁S2" }, 
// ...
], "complainTypeList": [{ "complaintTypeId": 2, "complaintTypeName": "客诉类型1", "createTime": "2019-10-10T12:07:54", "createUser": "", "enableState": 1, "id": 1, "updateTime": "2019-10-11T17:44:28", "updateUser": "", "version": 1 }, 
// ...
], "responsibleReasonList": [{ "createTime": "2019-10-10T12:11:07", "createUser": "", "enableState": 1, "feedbackReason": "反馈原因1", "feedbackReasonId": 2, "id": 1, "updateTime": "2019-10-10T12:11:07", "updateUser": "", "uploadImgState": 0, "uploadTimeState": 0, "version": 1 }, 
// ...
], "closeTicketList": [{ "createTime": null, "enableState": null, "id": null, "ruleBizTypeId": 5, "ruleDescription": null, "ruleId": 24, "ruleName": "客诉测试1", "updateTime": null }, 
// ...
], "useableStateList": [{ "id": 1, "name": "启用" }, { "id": 0, "name": "禁用" }] }
describe('完结规则-未选择数据点击提交', () => {
    const wrapper = mount(AddForm, {
        localVue,
        propsData: {
            selectArr: selectArr,
            arg: { productTypeId: '', complaintTypeId: '', feedbackReasonId: '3', droolsRuleList: '' }
        }
    })
    const vm = wrapper.vm
    const productItem = wrapper.find('form>div:nth-child(1)')
    const typeItem = wrapper.find('form>div:nth-child(2)')
    const reasonItem = wrapper.find('form>div:nth-child(3)')
    const closeItem = wrapper.find('form>div:nth-child(4)')
    /**
     * @description mock一个submit校验成功返回true失败返回false
     * @param {string} name - 表单名称
     * @returns {Boolean} - 校验结果
     */
    const mockFn = jest.fn(async (name) => {
        const result = await vm.$refs[name].validate()
        return result
    })
    wrapper.setMethods({ submit: mockFn })
    wrapper.find('form>div:nth-child(5) button').trigger('click');
    it('mockFn被调用1次', () => {
        // 断言mockFn被调用了两次次
        expect(mockFn).toHaveBeenCalledTimes(1);
    })
    it('产品子类未选,提示产品子类未选择', async () => {
        expect(productItem.contains('.ivu-form-item-error-tip'))
            .toBe(true)
    })
    it('客诉类型未选,提示客诉类型未选择', () => {
        expect(typeItem.contains('.ivu-form-item-error-tip'))
            .toBe(true)
    })
    it('反馈原因未选,提示反馈原因未选择', () => {
        expect(reasonItem.contains('.ivu-form-item-error-tip'))
            .toBe(true)
    })
    it('关单条件未选,提示关单条件未选择', () => {
        expect(closeItem.contains('.ivu-form-item-error-tip'))
            .toBe(true)
    })
})
describe('完结规则已选择数据-点击提交', () => {
    const wrapper = mount(AddForm, {
        localVue,
        propsData: {
            selectArr: selectArr,
            arg: { productTypeId: 9, complaintTypeId: 3, feedbackReasonId: 3, droolsRuleList: [25, 26] }
        }
    })
    const vm = wrapper.vm
    const productItem = wrapper.find('form>div:nth-child(1)')
    const typeItem = wrapper.find('form>div:nth-child(2)')
    const reasonItem = wrapper.find('form>div:nth-child(3)')
    const closeItem = wrapper.find('form>div:nth-child(4)')
    /**
     * @description mock一个submit校验成功返回true失败返回false
     * @param {string} name - 表单名称
     * @returns {Boolean} - 校验结果
     */
    const mockFn = jest.fn(async (name) => {
        const result = await vm.$refs[name].validate()
        return result
    })
    wrapper.setMethods({ submit: mockFn })
    wrapper.find('form>div:nth-child(5) button').trigger('click');
    it('mockFn被调用1次', () => {
        // 断言mockFn被调用了两次次
        expect(mockFn).toHaveBeenCalledTimes(1);
    })
    it('产品子类已选', async() => {
        await flushPromises()
        expect(productItem.html()).not.toContain('ivu-form-item-error-tip')
    })
    it('客诉类型已选', () => {
        expect(typeItem.html()).not.toContain('ivu-form-item-error-tip')
    })
    it('反馈原因已选', () => {
        expect(reasonItem.html()).not.toContain('ivu-form-item-error-tip')
    })
    it('关单条件已选', () => {
        expect(closeItem.html()).not.toContain('ivu-form-item-error-tip')
    })
})

校验结果
校验通过
校验的数据规则
在这里插入图片描述
子类已选且为字符串
选项不为数字
结果
输入数据不为数字
修改代码时修改错了参数名
在这里插入图片描述
结果
在这里插入图片描述

结论

关键地方可以进行单元测试。业务流程使用e2e较好

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值