经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » Vue.js » 查看文章
vue中如何使用jest单元测试
来源:jb51  时间:2022/8/15 16:59:31  对本文有异议

当我初次听到单元测试时,心里的第一感觉就两个字nb,然后就是疑惑,这是啥,干啥用,对代码又有什么帮助?接下来我会细细说一说我在学习以及应用单元测试的一些心得。(安装教程不再叙述,按照文档教程自行学习)

文档推荐

学习新知识,有中文文档当然是最好的啦!

组件挂载相关方法

shallowMount

shallowMount:

创建一个包含被挂载和渲染的 Vue 组件的 Wrapper。与之对应的还有一个mount。

shallowMount与mount的区别:

在文档中描述为"不同的是被存根的子组件",大白话就是shallowMount不会加载子组件,不会被子组件的行为属性影响该组件。

为什么使用shallowMount而不使用mount:

我认为单元测试的重点在"单元"二字,而不是"测试",想测试子组件再为子组件写对应的测试代码即可。

  1. import { shallowMount } from '@vue/test-utils'
  2. import Foo from './Foo.vue'
  3. describe('Foo', () => {
  4. ? ? const wrapper = shallowMount(Foo)
  5. })

Wrapper(这里只记录一些我经常使用的)

  • Wrapper:Wrapper 是一个包括了一个挂载组件或 vnode,以及测试该组件或 vnode 的方法。
  • Wrapper.vm:这是该 Vue 实例。你可以通过 wrapper.vm 访问一个实例所有的方法和属性。
  • Wrapper.classes:返回是否拥有该class的dom或者类名数组。
  • Wrapper.find:返回第一个满足条件的dom。
  • Wrapper.findAll:返回所有满足条件的dom。
  • Wrapper.html:返回html字符串。
  • Wrapper.text:返回内容字符串。
  • Wrapper.setData:设置该组件的初始data数据。
  • Wrapper.setProps:设置该组件的初始props数据。
  • Wrapper.trigger:用来触发事件。
  1. <template>
  2. ?? ?<div class="jest">
  3. ?? ??? ?<div class="name">{{name}}</div>
  4. ?? ??? ?<div class="name">{{name}}{{text}}</div>
  5. ?? ??? ?<div class="text" @click="add">{{text}}</div>
  6. ?? ?</div>
  7. </template>
  8. <script src="./script.js">
  9. export default {
  10. ?? ?name:"Foo",
  11. ?? ?props:{
  12. ?? ??? ?name:{
  13. ?? ??? ??? ?type: String,
  14. ?? ??? ??? ?default: '王大大'
  15. ?? ??? ?}
  16. ?? ?},
  17. ? ? data() {
  18. ? ? ? ? return {
  19. ? ? ? ? ? ? text: 123
  20. ? ? ? ? }
  21. ? ? },
  22. ? ? methods:{
  23. ? ? ?? ?add(){
  24. ?? ??? ??? ?this.text += 1
  25. ?? ??? ?}
  26. ? ? }
  27. }
  28. </script>
  1. import { shallowMount } from '@vue/test-utils'
  2. import Foo from './Foo.vue'
  3. describe('Foo', () => {
  4. ? ? const wrapper = shallowMount(Foo)
  5. ? ? console.log(Wrapper.classes())?? ?//['jest','name','test']
  6. ? ? console.log(Wrapper.classes('jest'))?? ?//true
  7. ? ? console.log(Wrapper.find('name').text())?? ?//返回第一个class是name的dom的内容 ? 王大大
  8. ? ? console.log(Wrapper.findAll('name'))?? ?//返回dom数组
  9. ? ? console.log(Wrapper.findAll('name').at(0))?? ?//取dom数组中的第一个
  10. ? ? Wrapper.setData({text : 1})
  11. ? ? console.log(Wrapper.vm.text)?? ?//1
  12. ? ? Wrapper.setProps({name : "李大大"})
  13. ? ? console.log(Wrapper.vm.name)?? ?//李大大
  14. ? ? Wrapper.find('text').trigger("click")
  15. ? ? console.log(Wrapper.vm.text) // 2
  16. })

挂载选项

就是shallowMount或者mount的时候可以设置一些初始化内容。具体可以初始化的全部内容请查询文章开始的文档。

  1. import { shallowMount } from '@vue/test-utils'
  2. import Foo from './Foo.vue'
  3. const wrapper = shallowMount(Foo, {
  4. ?? ?data() {
  5. ?? ??? ?return {
  6. ?? ??? ??? ?bar: 'my-override'
  7. ?? ??? ?}
  8. ? },
  9. ? propsData: {
  10. ?? ??? ?msg: 'aBC'
  11. ? }
  12. ? mocks: {
  13. ? ? ? ? $route: {
  14. ? ? ? ? ? ? query: {
  15. ? ? ? ? ? ? ? ? aaa: '1',
  16. ? ? ? ? ? ? }
  17. ? ? ? ? },
  18. ? ? ? ? $router: {
  19. ? ? ? ? ? ? push: jest.fn(),
  20. ? ? ? ? ? ? replace: jest.fn(),
  21. ? ? ? ? }
  22. ? ? }
  23. })

jest-api

匹配器

使用不同匹配器可以测试输入输出的值是否符合预期。

  • toBe:判断是否相等
  • toBeNull:判断是否为null
  • toBeUndefined:判断是否为undefined
  • toBeDefined:与上相反
  • toBeNaN:判断是否为NaN
  • toBeTruthy:判断是否为true
  • toBeFalsy:判断是否为false
  • toContain:数组用,检测是否包含
  • toHaveLength:数组用,检测数组长度
  • toEqual:对象用,检测是否相等
  • toThrow:异常匹配(没用过)
  1. describe('Foo', () => {
  2. ?? ?expect(2 + 2).toBe(4)
  3. ?? ?expect(null).toBeNull()
  4. ?? ?expect(undefined).toBeUndefined()
  5. ?? ?let a = 1;
  6. ?? ?expect(a).toBeDefined()
  7. ?? ?a = 'ada';
  8. ?? ?expect(a).toBeNaN()
  9. ?? ?a = true;
  10. ?? ?expect(a).toBeTruthy()
  11. ?? ?a = false;
  12. ?? ?expect(a).toBeFalsy()
  13. ?? ?a ?= [1,2,3];
  14. ?? ?expect(a).toContain(2)
  15. ?? ?expect(a).toHaveLength(3)
  16. ?? ?a = {a:1};
  17. ?? ?expect(a).toEqual({a:1})
  18. })

mock函数

例如:在一个vue组件中,ajax请求、路由跳转是常常用到的,但是在单测代码中,我们并不能正确的知道他是否执行并达到了预期的效果,这时就需要mock函数。在上文挂载选项中的mocks.$router就是一种mock函数的应用实例。

mock函数自然是要使用该函数,下面是一些函数的常用匹配器

  • toBeCalledTimes:判断函数被执行的次数
  • toBeCalled:判断函数是否被执行
  1. <template>
  2. ?? ?<div class="jest" @click="go"></div>
  3. </template>
  4. <script src="./script.js">
  5. export default {
  6. ?? ?name:"Foo",
  7. ? ? methods:{
  8. ? ? ?? ?go(){
  9. ?? ??? ??? ?this.$router.push({path:"/a"})
  10. ?? ??? ?}
  11. ? ? }
  12. }
  13. </script>
  1. import { shallowMount } from '@vue/test-utils'
  2. import Foo from './Foo.vue'
  3. const wrapper = shallowMount(Foo, {
  4. ? mocks: {
  5. ? ? ? ? $router: {
  6. ? ? ? ? ? ? push: jest.fn(),
  7. ? ? ? ? ? ? replace: jest.fn(),
  8. ? ? ? ? }
  9. ? ? }
  10. })
  11. wrapper.find(“jest").trigger("click");
  12. expect(wrapper.vm.$router.push).toBeCalled();
  13. wrapper.find(“jest").trigger("click");
  14. expect(wrapper.vm.$router.push).toBeCalledTimes(2);

promise模拟

  1. jest.mock('@root/api'); //模拟api请求函数
  2. import {getList} from '@root/api';
  3. const listJson = JSON.parse(require('fs').readFileSync('./mock/getList.json')); //引入mock好的json数据
  4. getList.mockResolvedValue(Promise.resolve(listJson)); //模拟promise返回
  5. getList().then(res => {
  6. ?? ?expect(res).toEqual(listJson);
  7. })

为什么要使用单测

说了这么多,那为什么要使用单测呢。在看完上面的描述我想大家也是一头郁闷,单测有用吗?答案当然是有。下面举个例子:

  1. <template>
  2. ?? ?<div class="jest"></div>
  3. </template>
  4. <script src="./script.js">
  5. import {getList} from '@root/api';
  6. export default {
  7. ?? ?name:"Foo",
  8. ? ? created(){
  9. ? ? ?? ?getList()
  10. ? ? ?? ?.then(res => {
  11. ? ? ?? ??? ?this.initData(res)
  12. ? ? ?? ?})
  13. ? ? },
  14. ? ? methods:{
  15. ?? ??? ?initData(data){
  16. ?? ??? ??? ?data.name = '王大大';
  17. ?? ??? ?}
  18. ?? ?}
  19. }
  20. </script>
  1. import { shallowMount } from '@vue/test-utils'
  2. import Foo from './Foo.vue'
  3. const wrapper = shallowMount(Foo)

这时候就会报错data.name,因为data不一定有值。正确案例如下

  1. <template>
  2. ?? ?<div class="jest"></div>
  3. </template>
  4. <script src="./script.js">
  5. import {getList} from '@root/api';
  6. export default {
  7. ?? ?name:"Foo",
  8. ? ? created(){
  9. ? ? ?? ?getList()
  10. ? ? ?? ?.then(res => {
  11. ? ? ?? ??? ?this.initData(res)
  12. ? ? ?? ?})
  13. ? ? },
  14. ? ? methods:{
  15. ?? ??? ?initData(data = {}){
  16. ?? ??? ??? ?data.name = '王大大';
  17. ?? ??? ?}
  18. ?? ?}
  19. }
  20. </script>

说白了就是让你的代码逻辑更符合预期结果。

总结

目前在vue中用到的一些基本知识都已经总结完了,如果以后在工作中使用了新的api,时间充裕的情况下我会持续更新。以上为个人经验,希望能给大家一个参考,也希望大家多多支持w3xue。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号