首頁 > 軟體

vue中如何使用jest單元測試

2022-08-15 18:02:05

當我初次聽到單元測試時,心裡的第一感覺就兩個字nb,然後就是疑惑,這是啥,幹啥用,對程式碼又有什麼幫助?接下來我會細細說一說我在學習以及應用單元測試的一些心得。(安裝教學不再敘述,按照檔案教學自行學習)

檔案推薦

學習新知識,有中文檔案當然是最好的啦!

元件掛載相關方法

shallowMount

shallowMount:

建立一個包含被掛載和渲染的 Vue 元件的 Wrapper。與之對應的還有一個mount。

shallowMount與mount的區別:

在檔案中描述為"不同的是被存根的子元件",大白話就是shallowMount不會載入子元件,不會被子元件的行為屬性影響該元件。

為什麼使用shallowMount而不使用mount:

我認為單元測試的重點在"單元"二字,而不是"測試",想測試子元件再為子元件寫對應的測試程式碼即可。

import { shallowMount } from '@vue/test-utils'
import Foo from './Foo.vue'
describe('Foo', () => {
    const wrapper = shallowMount(Foo)
})

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:用來觸發事件。
<template>
    <div class="jest">
        <div class="name">{{name}}</div>
        <div class="name">{{name}}{{text}}</div>
        <div class="text" @click="add">{{text}}</div>
    </div>
</template>
<script src="./script.js">
export default {
    name:"Foo",
    props:{
        name:{
            type: String,
            default: '王大大'
        }
    },
    data() {
        return {
            text: 123
        }
    },
    methods:{
        add(){
            this.text += 1
        }
    }
}
</script>
import { shallowMount } from '@vue/test-utils'
import Foo from './Foo.vue'
describe('Foo', () => {
    const wrapper = shallowMount(Foo)
    console.log(Wrapper.classes())    //['jest','name','test']
    console.log(Wrapper.classes('jest'))    //true
    console.log(Wrapper.find('name').text())    //返回第一個class是name的dom的內容   王大大
    console.log(Wrapper.findAll('name'))    //返回dom陣列
    console.log(Wrapper.findAll('name').at(0))    //取dom陣列中的第一個
    Wrapper.setData({text : 1})
    console.log(Wrapper.vm.text)    //1
    Wrapper.setProps({name : "李大大"})
    console.log(Wrapper.vm.name)    //李大大
    Wrapper.find('text').trigger("click")
    console.log(Wrapper.vm.text) // 2
})

掛載選項

就是shallowMount或者mount的時候可以設定一些初始化內容。具體可以初始化的全部內容請查詢文章開始的檔案。

import { shallowMount } from '@vue/test-utils'
import Foo from './Foo.vue'
const wrapper = shallowMount(Foo, {
    data() {
        return {
            bar: 'my-override'
        }
  },
  propsData: {
        msg: 'aBC'
  }
  mocks: {
        $route: {
            query: {
                aaa: '1',
            }
        },
        $router: {
            push: jest.fn(),
            replace: jest.fn(),
        }
    }
})

jest-api

匹配器

使用不同匹配器可以測試輸入輸出的值是否符合預期。

  • toBe:判斷是否相等
  • toBeNull:判斷是否為null
  • toBeUndefined:判斷是否為undefined
  • toBeDefined:與上相反
  • toBeNaN:判斷是否為NaN
  • toBeTruthy:判斷是否為true
  • toBeFalsy:判斷是否為false
  • toContain:陣列用,檢測是否包含
  • toHaveLength:陣列用,檢測陣列長度
  • toEqual:物件用,檢測是否相等
  • toThrow:異常匹配(沒用過)
describe('Foo', () => {
    expect(2 + 2).toBe(4)
    expect(null).toBeNull()
    expect(undefined).toBeUndefined()
    let a = 1;
    expect(a).toBeDefined()
    a = 'ada';
    expect(a).toBeNaN()
    a = true;
    expect(a).toBeTruthy()
    a = false;
    expect(a).toBeFalsy()
    a  = [1,2,3];
    expect(a).toContain(2)
    expect(a).toHaveLength(3)
    a = {a:1};
    expect(a).toEqual({a:1})
})

mock函數

例如:在一個vue元件中,ajax請求、路由跳轉是常常用到的,但是在單測程式碼中,我們並不能正確的知道他是否執行並達到了預期的效果,這時就需要mock函數。在上文掛載選項中的mocks.$router就是一種mock函數的應用範例。

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

  • toBeCalledTimes:判斷函數被執行的次數
  • toBeCalled:判斷函數是否被執行
<template>
    <div class="jest" @click="go"></div>
</template>
<script src="./script.js">
export default {
    name:"Foo",
    methods:{
        go(){
            this.$router.push({path:"/a"})
        }
    }
}
</script>
import { shallowMount } from '@vue/test-utils'
import Foo from './Foo.vue'
const wrapper = shallowMount(Foo, {
  mocks: {
        $router: {
            push: jest.fn(),
            replace: jest.fn(),
        }
    }
})
wrapper.find(「jest").trigger("click");
expect(wrapper.vm.$router.push).toBeCalled();
wrapper.find(「jest").trigger("click");
expect(wrapper.vm.$router.push).toBeCalledTimes(2);

promise模擬

jest.mock('@root/api'); //模擬api請求函數
import {getList} from '@root/api';
const listJson = JSON.parse(require('fs').readFileSync('./mock/getList.json')); //引入mock好的json資料
getList.mockResolvedValue(Promise.resolve(listJson)); //模擬promise返回
getList().then(res => {
    expect(res).toEqual(listJson);
})

為什麼要使用單測

說了這麼多,那為什麼要使用單測呢。在看完上面的描述我想大家也是一頭鬱悶,單測有用嗎?答案當然是有。下面舉個例子:

<template>
    <div class="jest"></div>
</template>
<script src="./script.js">
import {getList} from '@root/api';
export default {
    name:"Foo",
    created(){
        getList()
        .then(res => {
            this.initData(res)
        })
    },
    methods:{
        initData(data){
            data.name = '王大大';
        }
    }
}
</script>
import { shallowMount } from '@vue/test-utils'
import Foo from './Foo.vue'
const wrapper = shallowMount(Foo)

這時候就會報錯data.name,因為data不一定有值。正確案例如下

<template>
    <div class="jest"></div>
</template>
<script src="./script.js">
import {getList} from '@root/api';
export default {
    name:"Foo",
    created(){
        getList()
        .then(res => {
            this.initData(res)
        })
    },
    methods:{
        initData(data = {}){
            data.name = '王大大';
        }
    }
}
</script>

說白了就是讓你的程式碼邏輯更符合預期結果。

總結

目前在vue中用到的一些基本知識都已經總結完了,如果以後在工作中使用了新的api,時間充裕的情況下我會持續更新。以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com