[vue]前端测试

什么是前端测试

1.数据模拟与结果预测
2.实践模拟与结果或行为预测

测试的主要内容

  • 测试通用业务组件?业务变更快速,单元测试波动较大。X
  • 测试用户行为?用户行为存在上下文关系,组合起来是一个很恐怖的数字,这个交给测试人员去测就好了。X
  • 那到底该测什么呢?要测试主要是 功能型组件,vue插件,二次封装的库等等

例如断言组件的公共接口,测试用例将会断言一些输入 (用户交互或 prop 改变) 提供给某组件之后是否导致预期结果 (渲染结果或触发自定义事件)

组件测试不应该测什么

单纯测试组件模板中的 HTML

比如,测试组件模板中有几个 div、input、button,以及元素的 class、id 属性等与业务逻辑无关的纯 UI 测试。这里并非说我们不需要关注组件的 UI,而是出于以下几个考量:

  • 使用单元测试测试组件的 UI 会导致测试非常繁琐,为了测试覆盖的全面会导致针对一个组件写出大量的测试,不但降低了开发效率还体验非常差
  • 这种单纯的 UI 测试是非常脆弱的,这类测试和组件模板是强耦合的,一旦我们对 HTML 结构进行调整,测试就会挂掉,这就造成了测试非常难以维护。而实际上我们往往并不关心组件模板中的具体 HTML 结构是怎样的,我们只关心组件呈现出来的样子
  • 像 Jest 等前端测试框架已经提供了快照测试来帮助我们对比修改引起的 UI 变化,并且我们也可以使用Storybook这类工具实现可视化的 UI 测试

单元测试的作用

降低bug发生几率,快速定位bug,减少重复的手工测试。

提高代码质量,为项目带来更高的代码可维护性。

方便项目的交接工作,测试脚本就是最好的需求描述。

前端测试的种类

  • 单元测试
  • 集成测试
  • 端到端测试

测试工具

karma mocha chai sinon Jasmine Jest ava

添加测试设置

已经创建的项目添加test部分

添加@vue/cli 脚手架测试插件

vue add @vue/cli-plugin-unit-jest

已经使用了@vue/cli 脚手架的时候如何引入

vue invoke @vue/test-util

测试用例

vue2.x

jest.config.js

collectCoverageFrom

覆盖率涵盖的需要统计的文件,以及排除的文件

    collectCoverageFrom:[
        "**/src/**/**.{js,vue}",
        "!**/src/**.{js,vue}",
        "!**/src/config/**.{js,vue}",
        "!**/src/views/**/**.{js}",
        "!**/node_modules/**",
    ],

coverageDirectory

测试率覆盖报告输出目录

    coverageDirectory: '<rootDir>/tests/unit/coverage',

覆盖率报告说明

%Stmts(statement coverage): 语句覆盖率,是否每个语句都执行了
%Branch(branch coverage): 分支覆盖率,是否每个if代码块都执行了
%Funcs(branch coverage): 函数覆盖率,是否每个函数都调用了
%Lines(line coverage): 行覆盖率,是否每一行都执行了

组件测试

测试的组件中包含其它组件

问题:无法识别被测组件中的子组件
解决方案:在测试当前组件的时候需要注册当前组件引用的第三方组件或个人定义的当文件组件

import {createLocalVue, mount, shallowMount} from "@vue/test-utils";
const localVue = createLocalVue();
localVue.component("a-button",Button);

使用createLocalVue 是为了测试组件不污染全局设置

根据选择器获取元素个数

import {createLocalVue, mount, shallowMount} from "@vue/test-utils";
const localVue = createLocalVue();
localVue.use(Form);
expect(container.findAll('.ant-form-item').length).toEqual(3);

可测试的组件

vue add unit-jest

测试中存在属性变更使用

Vue.nextTick(()=>{
  
})

涉及路由的单元测试

为避免调用 Vue.use(…) 污染测试的全局命名空间,我们将会在测试中创建基础的路由;这让我们能在单元测试期间更细粒度的控制应用的状态。
因此使用createLocalVue创建本地vue

const localVue = createLocalVue();
localVue.use(VueRouter);

这里可以使用use,但是使用use注册组件却有问题

localVue.use(Result).use(Button);

发生报错信息

[Vue warn]: Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the “name” option.

发现use的使用只适用部分内容;
对于引用第三方的组件有的是不适用的,通过实践发现以下方式可行:

localVue.component("a-result",Result);
localVue.component("a-button",Button);

另一个要注意的是这里用了 mount 而非 shallowMount。如果用了 shallowMount,则 就会被忽略,不管当前路由是什么,渲染的其实都是一个无用的替身组件。

mount和shallowMount的区别

mount仅仅挂载当前组件实例;而shallowMount挂载当前组件实例以外,还会挂载子组件。

包含路由组件

No-fond 组件

传递属性则组件显示传递值

如果没有传递则显示默认值

<template>
    <a-result
            :status="status"
            :title="title"
            :subTitle="subTitle"
    >
        <template v-slot:extra>
            <router-link to="/index">
                <a-button type="primary" link>Back Home</a-button>
            </router-link>
        </template>
    </a-result>
</template>

<script>
    export default {
        name: "no-find",
        props: ["otherStatus", "otherTitle", "otherSubTitle"],
        data(){
            return {
                status: (this.otherStatus == undefined ? "404" : this.otherStatus),
                title: this.otherTitle == undefined ? '404' : this.otherTitle,
                subTitle: this.otherSubTitle == undefined ? "Sorry, the page you visited does not exist." : this.otherSubTitle
            }
        }
    };
</script>

1.使用shallowMount可以识别router-link,mount无法识别router-link
2.shallowMount能够渲染最外层组件,无法获取解析后的子组件,mount可以获取解析后的子组件
3.如果需要使用mount,但是也包含router-link:

  • 创建路由
  • 将路由作为参数
const router = new VueRouter({ myRouter });
const wrapper = mount(NoFound,{
    localVue,
    router
});
expect(wrapper.findComponent(Result).html()).toContain("Sorry, the page you visited does not exist");

如何测试触发router-link路由跳转,这块还不太清楚

Error in mounted hook

computed: {
    //这里需要把store 动态的数据放到computed里面才会同步更新 视图
    getChannels() {
        return this.$store.state.channelList
    }
}
return this.$store.getters.getChannelList;

vue组件中methods方法的测试

测试组件的内部方法

[vue-test-utils]: overwriting methods via the methods property is deprecated and will be removed in the next major version. There is no clear migration path
for the methods property - Vue does not support arbitrarily replacement of methods, nor should VTU. To stub a complex method extract it from the component and te
st it in isolation. Otherwise, the suggestion is to rethink those tests

如果一些方法只是在组件内部调用其他方法而没有任何暴露给外部的行为(比如更改了组件的 UI、请求外部 API 等),那这些方法是不需要测试的。我们希望一个组件就像一个黑盒一样,我们不关心其内部的处理逻辑而只关注其外部呈现。

表单变更等触发的方法

input

通过设置input的值
调用触发方法

textInput.element.value = value
textInput.trigger(‘input’)

select

select.element.value = value
select.trigger(‘change’)

生命周期中调用methods的测试

shallow(TestComp, { methods: {testMethod: () => {}}  }))

该种方法目前已废弃
在created()中调用异步函数
在mounted()调用异步函数

{
    localVue,
     mounted(){//该方法执行可是调用的异步仍旧执行了}
 }
let spy = jest.spyOn(Index.methods, 'getCategoryData');
container = shallowMount(Index,options);

没有stub getCategoryData

测试中异步交互的模拟

jest.mock('axios', () => ({
    get: jest.fn(() => Promise.resolve({
        "resCode": "200",
        "resMessage": "get_info success",
        "data": ["C", "R"]
    }))
}));
import axios from 'axios';

测试通过,这个主要是用于模拟触发的异步方法

这里的’axios’不是install安装的axios,而是mock的axios,所以import axios一定要在jest.mock(‘axios’)语句后

mock data

这个如果直接使用data就不需要模拟

store 使用的测试

这个可以直接参考官网,比较清晰明确

测试博客

之前看到的比较好的测试相关内容

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三知之灵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值