單元測試從零開始,包含 Vue 及 React 項目中該如何單測

前言

本文取自筆者的開源項目 前端進階之路javascript

有興趣的能夠了解一下,目前還在寫做中。css

正文

在這部分的內容中,你將學習到如下幾點:html

  • 單元測試的做用
  • 最應該對哪些模塊進行單元測試
  • React 和 Vue 這兩大框架的單元測試學習路徑
  • 如何在 React 和 Vue 這兩大框架中進行單元測試以及 Demo 實戰

單元測試是用來測試程序中一小塊功能的,好比說一個函數、一個類。它能很顯著地提升項目的代碼質量,下降出現 Bug 的頻率,而且也利於維護代碼。前端

可是實際狀況是絕大部分開發者是不肯意作這件事情的。由於平時開發都忙不過來,哪還有時間去作這些事情。vue

我我的其實認爲業務代碼的測試應該是不強求的,畢竟需求常常在變化。若是對業務代碼進行高覆蓋率的測試,那麼一旦需求變更就須要同步修改測試用例。這樣編碼的壓力是雙份的,極可能達不到快節奏上線的目的。java

可是對於依賴的基礎組件庫以及公共函數是必定須要編寫單元測試的。由於這些內容會被多個模塊使用到,而且也不會頻繁變動這些基礎的功能,編寫單元測試的收益相對來講高得多。就好比各類知名的開源項目的測試覆蓋率每每是高於 90% 的,測試覆蓋率低或者壓根不寫測試的開源項目通常不多直接用於項目中。node

那麼咱們如何學習這方面的內容呢?首先不管你使用什麼技術棧,都須要先選擇一個測試框架。Jest 是其中一個相對來講優秀的框架(不少知名開源項目也都在使用它),開箱即用,內部集成了斷言庫、Mock、快照功能等等。固然你也能夠一樣選擇別的框架,核心內容都是同樣的,無非 API 有所改變罷了。react

Jest 入門

Jest 總歸是個使用起來很簡單的框架,不須要太多的學習時間就能上手了。另外若是你想學習如何用好這個框架,最好的辦法實際上是閱讀工具庫以及組件庫的測試用例。git

如下是對 Jest 一些重要功能的簡單介紹。github

斷言

在 Jest 中使用最多的就是內部的斷言庫了,由於咱們須要用它來測試函數的輸出是否與咱們預期的一致。

它的用法也很簡單,你稍微會點英文就能看懂一段測試代碼的用途,甚至於不須要去翻閱文檔。好比說你指望一個函數的輸出爲 2

// 翻譯出來就是我測試一段代碼,指望函數(輸入)等於我指望的輸出
test('測試 1 + 1 = 2', () => {
  expect(sum(1, 1)).toBe(2)
})
複製代碼

關於這部分的內容你們只須要翻閱下文檔就能熟練使用了。

異步代碼測試

異步獲取數據確定是一個常見場景了。異步代碼一般會有兩種寫法,分別爲:

  • 回調函數
  • 函數返回 promise

在測試異步代碼的時候,一般返回的數據是不肯定的,所以咱們只須要測試異步代碼是否正常返回數據便可。

// 回調函數的寫法,經過 done 來讓測試代碼一直等待
test('fetch success', done => {
  fetch(data => {
    expect(data.success).toBe(true)
    done()
  })
})
// 函數返回 promise 的寫法,注意要加上 return
// 固然對於返回 promise 的函數咱們也能夠直接使用 await
test('fetch success', () => {
  return fetch().then(data => {
    expect(data.success).toBe(true)
  })
})
複製代碼

Mock 函數

假設咱們須要測試一個回調函數是否被執行、參數或者返回值是否正確,這時候咱們就可使用 Mock 函數。

function foo(cb) {
  cb(1)
}
const mockCallback = jest.fn(value => value + 1)
// 回調被調用
expect(mockCallback).toBeCalled()
// 回調函數參數爲 1
expect(mockCallback.mock.calls[0][0]).toBe(1)
// 回調函數返回值爲 2
expect(mockCallback.mock.results[0].value).toBe(2)
複製代碼

固然 Mock 函數還有更多用法。好比模擬返回值,追蹤函數被調用的各類狀況等等,更多的內容能夠閱讀文檔去學習。

快照

快照在測試組件時是個頗有用的功能,能夠幫助咱們確保在維護代碼的過程當中不會對組件的 UI 進行改變。

用法至關簡單:

expect(組件實例).toMatchSnapshot()
複製代碼

以上代碼在第一次執行時會生成快照,在接下來的測試中每次都會去對比二者的內容是否一致。

配置文件

Jest 和 Babel 同樣,使用的時候都須要一個配置文件。對於 Jest 來講,你須要在根目錄中建立一個名爲 jest.config.js 的文件。

如下是一些常見的配置選項:

module.exports = {
  // 文件後綴
  moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
  // 文件如何轉換
  transform: {
    '^.+\\.vue$': 'vue-jest',
    '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
      'jest-transform-stub',
    '^.+\\.jsx?$': 'babel-jest'
  },
  // 忽略的文件
  transformIgnorePatterns: ['/node_modules/'],
  // 生成快照須要的插件
  snapshotSerializers: ['jest-serializer-vue'],
  // 須要執行哪些目錄下的測試用例
  testMatch: [
    '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
  ],
  // 在執行用例前的配置文件
  setupFiles: ['./tests/setup.js'],
  // 測試覆蓋率配置
  collectCoverage: true,
  coverageReporters: ['html', 'lcov', 'text-summary'],
  coverageDirectory: './test/coverage',
  collectCoverageFrom: ['components/**/*.vue']
}
複製代碼

更多的配置屬性能夠查閱文檔學習。

怎麼對工具函數進行單測

對於工具函數來講,首要一點就是這個函數不能包含太多的功能,拆分紅一個個功能函數是最佳的方式,由於這樣測試起來會很方便。

另外對於工具函數來講,輸出應該是可控的,因此寫單測起來很容易,只須要 except 函數的輸出便可。

怎麼對組件進行單測

對於組件來講,最重要的是爲組件生成各個狀態下的快照,以防代碼變更後引起 UI 層面的 Bug。剩餘的內容就是對各個功能進行測試了,好比說值設置的對不對啦、事件有沒有響應啦、邏輯是否是正確啦等等,這部分的測試主要還要看具體組件的功能了。

另外若是你有作統計測試覆蓋率的話,會發現 Branch 指標的提高每每是最難的對於組件來講。一旦你能把這個指標提高到 95% 以上,那麼這個組件的問題會少不少。

Vue 中實踐 Jest

推薦在完成環境配置後閱讀該文檔

本小結 demo 地址

配置

無論你是現有項目仍是新項目須要使用 Jest,均可以經過 Vue Cli 3 解決。

對於現有項目,只須要在項目文件夾中執行一條命令便可

vue add unit-jest
複製代碼

腳手架會自動在項目中幫你安裝 Jest 須要的配置,安裝完成後你會發現根目錄中新增了一個文件夾

文件夾中包含了一個測試用例,你只需執行 yarn test:unit 便可運行測試用例。

對於新項目來講,在建立項目過程當中須要選擇 Manually select features,而後按照如下內容選擇便可集成 Jest 環境。

實踐

完成環境配置之後咱們就開始進行一個簡單的組件測試吧。

PS:組件測試須要用到 @vue/test-utils 這個庫,由於須要它來幫助咱們 mount 組件以及對組件進行一系列的操做。當組件掛載之後,咱們就能夠經過 Jest 進行斷言、Mock、生成快照等等。

在 components 文件夾下咱們新增一個 loading.vue 文件

<template>
  <div class="loading"> <span class="loading__indicator" :style="style" /> <span class="loading__text" v-show="text">{{ text }}</span> </div>
</template>

<script> export default { props: { text: String, size: { type: Number, default: 26 }, indicatorColor: { type: String, default: "#1989FA" } }, computed: { style() { return { width: this.size + "px", height: this.size + "px", borderColor: this.indicatorColor, borderBottomColor: "transparent" }; } } }; </script>
複製代碼

以上代碼是一個很簡單的組件,傳入 props 就完成了整個組件的渲染,沒有其餘的邏輯了。

測試用例也很簡單,完成對全部的 props 輸入輸出對比便可實現 100% 的測試覆蓋率。

describe('Loading.vue', () => {
  it('renders props.msg when passed', () => {
    const wrapper = mount(Loading, {
      propsData: {
        text: 'Loading',
        indicatorColor: 'red',
        size: 20
      }
    })
    const indicatorStyle = wrapper.find('.loading__indicator').element.style
    expect(wrapper.find('.loading__text').text()).toBe('Loading')
    expect(indicatorStyle.borderColor).toContain('red')
    expect(indicatorStyle.width).toContain('20px')
  })
  it('snapshot', () => {
    const wrapper = mount(Loading, {
      propsData: {
        text: 'Loading',
        indicatorColor: 'red',
        size: 20
      }
    })
    expect(wrapper).toMatchSnapshot()
  })
})
複製代碼

執行 yarn test:unit 命令後,咱們應該能見到以下圖的內容

若是你想更進一步學習在 Vue 中進行單元測試的內容,推薦如下資料:

React 中實踐 Jest

推薦在完成環境配置後閱讀該文檔

本小結 demo 地址

配置

對於新項目來講,若是你使用 create-react-app 的話,那麼默認 Jest 就集成在內部了,你只須要運行命令 yarn eject 就能夠在 package.json 文件中看到 Jest 的配置。

對於現有項目來講,你能夠經過個人 demo 或者這篇文章來學習相關的配置,這裏就再也不贅述了。

另外可能有些同窗是 TS 的環境,所以個人 Demo 中是以 TS 爲基礎配置的。

實踐

PS:組件測試須要用到 enzyme 以及 enzyme-adapter-react-16 這兩個庫,由於須要它們來幫助咱們 mount 組件以及對組件進行一系列的操做。當組件掛載之後,咱們就能夠經過 Jest 進行斷言、Mock、生成快照等等。

另外鑑於組件測試這塊的內容基本和 Vue 中的一致,所以這裏就不浪費篇幅複製代碼了,具體內容能夠去 demo 中學習。

若是你想更進一步學習在 React 中進行單元測試的內容,推薦如下資料:

總結

總的來講在項目中進行單元測試須要學習的內容並很少,一個 Jest 外加一個可以掛載組件的庫便可,一天既能上手這塊的內容。

真正須要花時間學習的應該仍是閱讀優秀第三方庫的測試用例上。

相關文章
相關標籤/搜索