亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

淺談Vue組件單元測(cè)試究竟測(cè)試什么

 更新時(shí)間:2020年02月05日 14:40:02   作者:KaysonLi  
這篇文章主要介紹了淺談Vue組件單元測(cè)試究竟測(cè)試什么,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

關(guān)于 Vue 組件單元測(cè)試最常見的問題就是“我究竟應(yīng)該測(cè)試什么?”

雖然測(cè)試過多或過少都是可能的,但我的觀察是,開發(fā)人員通常會(huì)測(cè)試過頭。畢竟,沒有人愿意自己的組件未經(jīng)測(cè)試從而導(dǎo)致應(yīng)用程序在生產(chǎn)中崩潰。

在本文中,我將分享一些用于組件單元測(cè)試的指導(dǎo)原則,這些指導(dǎo)原則可以確保在編寫測(cè)試上不會(huì)花費(fèi)大量時(shí)間,但是可以提供足夠的覆蓋率來避免錯(cuò)誤。

本文假設(shè)你已經(jīng)了解 Jest 和 Vue Test Utils。

示例組件

在學(xué)習(xí)這些指導(dǎo)原則之前,我們先來熟悉下要測(cè)試的示例組件。組件名為 Item.vue ,是 eCommerce App 里的一個(gè)產(chǎn)品條目。

下面是組件的源碼。注意有三個(gè)依賴項(xiàng):Vuex ( $store ), Vue Router ( $router ) 和 Vue Auth ( $auth )。

Item.vue

<template>
 <div>
 <h2>{{ item.title }}</h2>
 <button @click="addToCart">Add To Cart</button>
 <img :src="item.image"/>
 </div>
</template>
<script>
export default {
 name: "Item",
 props: [ "id" ],
 computed: {
 item () {
  return this.$store.state.find(
  item => item.id === this.id
  );
 }
 },
 methods: {
 addToCart () {
  if (this.$auth.check()) {
  this.$store.commit("ADD_TO_CART", this.id);
  } else {
  this.$router.push({ name: "login" });
  }
 }
 }
};
</script>

配置 Spec 文件

下面是測(cè)試用的 spec 文件。其中,我們將用 Vue Test Utils “淺掛載”示例組件,因此引入了相關(guān)模塊以及我們要測(cè)試的 Item 組件。

同時(shí)還寫了一個(gè)工廠函數(shù)用于生成可覆蓋的配置對(duì)象,以免在每個(gè)測(cè)試中都需要指定 props 和 mock 三個(gè)依賴項(xiàng)。 item.spec.js

import { shallowMount } from "@vue/test-utils";
import Item from "@/components/Item";

function createConfig (overrides) {
 const id = 1;
 const mocks = {
 // Vue Auth
 $auth: {
  check: () => false
 },
 // Vue Router
 $router: {
  push: () => {}
 },
 // Vuex
 $store: {
  state: [ { id } ],
  commit: () => {}
 }
 };
 const propsData = { id };
 return Object.assign({ mocks, propsData }, overrides);
}

describe("Item.vue", () => {
 // Tests go here
});

確定業(yè)務(wù)邏輯

對(duì)于要測(cè)試的組件,要問的第一個(gè)也是最重要的問題是“業(yè)務(wù)邏輯是什么”,即組件是做什么的?

對(duì)于這個(gè) Item.vue ,業(yè)務(wù)邏輯是:

  • 根據(jù)接收的id屬性展示條目信息
  • 如果用戶是訪客,點(diǎn)擊 Add to Cart 按鈕將重定向到登錄頁
  • 如果用戶已登錄,點(diǎn)擊 Add to Cart 按鈕會(huì)觸發(fā) Vuex mutation ADD_TO_CART。

確定輸入和輸出

當(dāng)你對(duì)組件做單元測(cè)試時(shí),可將其視為一個(gè)黑盒。方法、計(jì)算屬性等內(nèi)部邏輯只影響輸出。

因此,下一個(gè)重點(diǎn)是確定組件的輸入和輸出,因?yàn)檫@些也是測(cè)試的輸入和輸出。

Item.vue 的輸入是:

  • id 屬性
  • 來自 Vuex 和 Vue Auth 的數(shù)據(jù)狀態(tài)
  • 用戶點(diǎn)擊按鈕

輸出是:

  • 渲染后的 HTML
  • 發(fā)送到 Vuex mutation 或者 Vue Router push 的數(shù)據(jù)

有些組件也會(huì)將表單和事件作為輸入,觸發(fā)事件作為輸出。

測(cè)試 1: 訪客點(diǎn)擊按鈕跳轉(zhuǎn)路由

有一個(gè)業(yè)務(wù)邏輯是“如果用戶是訪客,點(diǎn)擊 Add to Cart 按鈕將重定向到登錄頁”。我們來寫這個(gè)測(cè)試。

我們通過“shallow mount”組件來編寫測(cè)試,然后找到并點(diǎn)擊 Add to Cart 按鈕。

test("router called when guest clicks button", () => {
 const config = createConfig();
 const wrapper = shallowMount(Item, config);
 wrapper
 .find("button")
 .trigger("click");
 // Assertion goes here
}

隨后我們會(huì)加上 assertion。

不要超出輸入和輸出的界限

在這個(gè)測(cè)試中很容易采取的做法是在點(diǎn)擊按鈕后判斷路由是否跳轉(zhuǎn)到了登錄頁,比如:

import router from "router";

test("router called when guest clicks button", () => {
 ...
 // 錯(cuò)!
 const route = router.find(route => route.name === "login");
 expect(wrapper.vm.$route.path).toBe(route.path);
}

雖然這確實(shí)也能測(cè)試組件的輸出,但是它依賴于路由功能,這不應(yīng)該是組件所關(guān)心的。

直接測(cè)試組件的輸出會(huì)更好,也就是調(diào)用了 $router.push 。至于路由是否最終完成了操作,這已經(jīng)超出了本測(cè)試的范疇。

因此我們可以監(jiān)聽路由的 push 方法,并斷言它是否被登錄路由對(duì)象調(diào)用。

import router from "router";

test("router called when guest clicks button", () => {
 ...
 jest.spyOn(config.mocks.$router, "push");
 const route = router.find(route => route.name === "login");
 expect(spy).toHaveBeenCalledWith(route);
}

測(cè)試 2: 登錄用戶點(diǎn)擊按鈕后調(diào)用 vuex

接下來讓我們測(cè)試業(yè)務(wù)邏輯“如果用戶已登錄,點(diǎn)擊 Add to Cart 按鈕將觸發(fā) Vuex mutation ADD_TO_CART ”。

同樣,你不需要判斷 Vuex 狀態(tài)是否更改了。要驗(yàn)證這個(gè)需要另外單獨(dú)測(cè)試 Vuex store。

組件的職責(zé)只是執(zhí)行 commit,因此我們只要測(cè)試這個(gè)動(dòng)作就行。

首先重寫 $auth.check 假數(shù)據(jù)讓它返回  true (模擬登錄用戶)。然后監(jiān)聽 store 的  commit 方法,并斷言點(diǎn)擊按鈕后被調(diào)用。

test("vuex called when auth user clicks button", () => {
 const config = createConfig({
 mocks: {
  $auth: {
  check: () => true
  }
 }
 });
 const spy = jest.spyOn(config.mocks.$store, "commit");
 const wrapper = shallowMount(Item, config);
 wrapper
 .find("button")
 .trigger("click");
 expect(spy).toHaveBeenCalled();
}

不要測(cè)試其他庫的功能

Item 組件展示條目數(shù)據(jù),特別是標(biāo)題和圖片?;蛟S我們應(yīng)該寫一個(gè)測(cè)試來專門檢查這些?比如:

test("renders correctly", () => {
 const wrapper = shallowMount(Item, createConfig());
 // Wrong
 expect(wrapper.find("h2").text()).toBe(item.title);
}

這又是一個(gè)不必要的測(cè)試,因?yàn)樗皇菧y(cè)試了 Vue 從 Vuex 中提取數(shù)據(jù)并插入到模板的能力。Vue 這個(gè)庫已經(jīng)對(duì)該機(jī)制進(jìn)行了測(cè)試,所以你應(yīng)該依賴于它。

測(cè)試 3: 正確地渲染

但是等等,如果有人不小心將 title 重命名為 name ,然后忘記更新插值表達(dá)式怎么辦?這難道不需要測(cè)試嗎?

沒錯(cuò),但是如果你像這樣來測(cè)試模板的方方面面,何時(shí)才是個(gè)頭?

測(cè)試 HTML 最好的辦法是使用快照,用來檢查整體渲染后的結(jié)果。這不僅覆蓋了標(biāo)題插值,還包括圖片、按鈕文本、任何 class 等。

test("renders correctly", () => {
 const wrapper = shallowMount(Item, createConfig());
 expect(wrapper).toMatchSnapshot();
});

其他不需要測(cè)試的點(diǎn)還有這些:

  • src 屬性是否綁定到 img 元素
  • 添加到 Vuex store 中的數(shù)據(jù)是否跟插入的數(shù)據(jù)一致
  • 計(jì)算屬性是否返回了正確的數(shù)據(jù)
  • 執(zhí)行 router push 是否重定向到正確的頁面

諸如此類。

總結(jié)

我認(rèn)為上面三個(gè)簡單的測(cè)試對(duì)這個(gè)組件來說足夠了。
組件單元測(cè)試的一個(gè)好理念是先假設(shè)測(cè)試是不必要的,除非被證明是必要的。

你可以問自己以下問題:

  • 這是業(yè)務(wù)邏輯的一部分嗎?
  • 這是直接測(cè)試組件的輸入和輸出嗎?
  • 這是測(cè)試自己的代碼,還是第三方代碼?

讓我們愉快地單元測(cè)試吧!希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • vue-cli創(chuàng)建項(xiàng)目ERROR?in?Conflict:?Multiple?assets?emit?different?content?to?the?same?filename?index.html問題的解決辦法

    vue-cli創(chuàng)建項(xiàng)目ERROR?in?Conflict:?Multiple?assets?emit?dif

    最近vue/cli創(chuàng)建項(xiàng)目后出現(xiàn)了錯(cuò)誤,下面這篇文章主要給大家介紹了關(guān)于vue-cli創(chuàng)建項(xiàng)目ERROR?in?Conflict:?Multiple?assets?emit?different?content?to?the?same?filename?index.html問題的解決辦法,需要的朋友可以參考下
    2023-02-02
  • vue3?+?antv/x6實(shí)現(xiàn)流程圖的全過程

    vue3?+?antv/x6實(shí)現(xiàn)流程圖的全過程

    隨著互聯(lián)網(wǎng)的發(fā)展,越來越多的應(yīng)用需要實(shí)現(xiàn)流程圖的制作,如工作流程圖、電路圖等,文中通過代碼以及圖文將實(shí)現(xiàn)的過程介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2024-06-06
  • axios請(qǐng)求二次封裝之避免重復(fù)發(fā)送請(qǐng)求

    axios請(qǐng)求二次封裝之避免重復(fù)發(fā)送請(qǐng)求

    在做vue中大型項(xiàng)目的時(shí)候,官方推薦使用axios,但是原生的axios可能對(duì)項(xiàng)目的適配不友好,所以在工程開始的來封裝一下axios,下面這篇文章主要給大家介紹了關(guān)于axios請(qǐng)求二次封裝之避免重復(fù)發(fā)送請(qǐng)求的相關(guān)資料,需要的朋友可以參考下
    2022-10-10
  • vue前端實(shí)現(xiàn)導(dǎo)出頁面為word的兩種方法代碼

    vue前端實(shí)現(xiàn)導(dǎo)出頁面為word的兩種方法代碼

    在前端開發(fā)中我們常常需要將頁面頁面為word文件,這篇文章主要給大家介紹了關(guān)于vue前端實(shí)現(xiàn)導(dǎo)出頁面為word的兩種方法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-04-04
  • 詳解處理Vue單頁面應(yīng)用SEO的另一種思路

    詳解處理Vue單頁面應(yīng)用SEO的另一種思路

    這篇文章主要介紹了詳解處理Vue單頁面應(yīng)用SEO的另一種思路,本文主要針對(duì) vue 2.0 單頁面 Meta SEO 優(yōu)化展開介紹,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2018-11-11
  • Vue3快速diff算法的處理過程

    Vue3快速diff算法的處理過程

    傳統(tǒng)的?DOM?更新方法會(huì)在有新舊子節(jié)點(diǎn)時(shí)卸載舊節(jié)點(diǎn)并掛載新節(jié)點(diǎn),這種方法沒有考慮到節(jié)點(diǎn)的復(fù)用可能性,diff?算法通過比較新舊節(jié)點(diǎn)的差異來復(fù)用節(jié)點(diǎn),從而優(yōu)化性能,本文給大家介紹了Vue3快速diff算法的處理過程,需要的朋友可以參考下
    2024-05-05
  • 前端vue3項(xiàng)目中百度地圖的使用api以及操作實(shí)例

    前端vue3項(xiàng)目中百度地圖的使用api以及操作實(shí)例

    最近項(xiàng)目要用到百度地圖api,好久沒用到地圖,就百度了一番,但是找了好幾篇文章,發(fā)現(xiàn)都沒辦法成功實(shí)現(xiàn),現(xiàn)將方法記錄如下,下面這篇文章主要給大家介紹了關(guān)于前端vue3項(xiàng)目中百度地圖的使用api以及操作實(shí)例,需要的朋友可以參考下
    2023-05-05
  • vue滾動(dòng)固定頂部及修改樣式的實(shí)例代碼

    vue滾動(dòng)固定頂部及修改樣式的實(shí)例代碼

    這篇文章主要介紹了vue滾動(dòng)固定頂部及修改樣式,本文給大家提到了滾動(dòng)固定位置有多種方法,感興趣的朋友跟隨小編一起看看吧
    2019-05-05
  • vue3.0實(shí)現(xiàn)下拉菜單的封裝

    vue3.0實(shí)現(xiàn)下拉菜單的封裝

    這篇文章主要為大家詳細(xì)介紹了vue3.0實(shí)現(xiàn)下拉菜單的封裝代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • 如何使用 Vue Router 的 meta 屬性實(shí)現(xiàn)多種功能

    如何使用 Vue Router 的 meta 屬性實(shí)現(xiàn)多種功能

    在Vue.js中,Vue Router 提供了強(qiáng)大的路由管理功能,通過meta屬性,我們可以在路由定義中添加自定義元數(shù)據(jù),以實(shí)現(xiàn)訪問控制、頁面標(biāo)題設(shè)置、角色權(quán)限管理、頁面過渡效果,本文將總結(jié)如何使用 meta 屬性來實(shí)現(xiàn)這些常見的功能,感興趣的朋友一起看看吧
    2024-06-06

最新評(píng)論