iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 26
1
Modern Web

忍住不打牌位,只要30天VueJS帶你上A牌系列 第 26

Day26 單元測試 unit test

前言

在寫測試之前,或許在過往我們都是:

1.想使用情境 -> 寫程式邏輯 -> 無招勝有招,不寫測試

2.想使用情境 -> 寫程式邏輯 -> 寫單元測試

我曾在台灣前端FB社團裡面看到調查,竟然絕大多數的工程師是不寫測試的,我的老天鵝阿,這其實在台灣很顯然的是不被重視的一塊,就連我的前主管也覺得["寫單元測試只是再多寫一次code,不合成本"];
再或者,有的人寫測試不是真的想測試,而是為了要有測試而寫測試,maybe今天公司是有CI/CD的制度,所以為了有單元測試的腳本,就來寫很沒意義的測試expect(true).toBe(true),這種就是在做交代而已,良心好一點就可以還會再測的幾個有意義的...,像極了水電工在電器引接地線,但最後接地線有沒有用接地銅管埋到地下,痾!不得而知。

我們又何必當個做表面的人呢?如果今天有一個方式可以讓你有測試,也有好品質的程式,您願不願意試看看,不知道大家有沒有聽過測試區動開發(TDD)。

Test-Driven Development

TDD是一種開發流程,中文是「測試驅動開發」。白話文就是「先寫測試再開發」,先寫測試除了能確保測試程式的撰寫,也有助於在開發初期更清楚介面如何設計。

Wikipedia Test-Driven Development

現在想給大家另一個角度來開發,也就是我們何不嘗試先寫測試,在來寫程式呢?
這或許對很多人來說一開始很不習慣,包含我也是(小聲

整體步驟大略來說:
想使用情境 -> 寫測試案例 -> 寫程式邏輯
整體步驟細分來說:
選定使用情境下個功能,新增一個測試案例 -> 執行測試得到failed -> 實作夠用的程式 -> 再次執行測試得到passed -> 進入重構程式 -> 重複以上步驟

Vue unit test

安裝步驟,在一開始初始化專案時已經完成,詳細安裝,我是用Jest來做單元測試。
1.選定使用情境下個功能,新增一個測試案例
今天情境是使用者上傳檔案,在介面上需要顯示出來,第一個測試案例是來做個檔案大小的轉換。
首先在test/unit底下新增OOO.spec.js、OOO.js
|- OOO.js Function
|- OOO.spec.js Function的測試腳本
再來是撰寫測試案例

import fileUpload from './fileUpload.js';

describe('fileUpload', () => {

  test('上傳檔案大小要轉換單位', () => {
    let bytes = 1024;
    expect(company.formatSize(bytes)).toBe('1 KB');
  });

})

補充一下斷言,我們會使用預期expect(受測的函數),斷言它應該要是甚麼值
tobe:多用在比較原始型別,如string、number、boolean
toEqual:若用在比較原始型別,與tobe一樣,但大多數用在比較Object、Array,它會去深層比較物件、陣列裡的每一個值是否相等。
toStrictEqual:比toEqual更嚴格比較:

  • 針對undefined屬性檢查,如{a: undefined, b: 2}不等於{b: 2}
  • 針對陣列稀疏性檢查,舉例來說[, 1]也不等於[undefined, 1]
  • 針對物件類型檢查,如類實例的物件也不等於文字物件
    延伸學習Jest

2.執行測試得到failed
npm run test 得到失敗,我們還沒實作程式,理所當然是Failed
3.實作夠用的程式
在這個步驟不用太著墨程式碼,而是專注在功能邏輯的實作。

const fileUpload = {

  formatSize(bytes) {
    let k = 1024,
    sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
    i = Math.floor(Math.log(bytes) / Math.log(k));

    return parseFloat((bytes / Math.pow(k, i))) + ' ' + sizes[i];
  }

export default fileUpload;

4.再次執行測試得到passed
npm run test 得到成功,若遇到失敗在重新檢視程式碼,確保執行邏輯正常。
5.進入重構程式
為了更好的程式品質,避免維護成本及技術債,做適當的重構程式,寫進去Vue裡

const fileUpload = {

  formatSize (bytes) {
    if (bytes === 0) {
      return '0 B'
    }
    const k = 1024
    const dm = 3
    const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
    const i = Math.floor(Math.log(bytes) / Math.log(k))

    return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]
  },

export default fileUpload;

6.重複以上步驟,繼續開發

一般開發流程 vs 測試區動開發

我在幫別人code review的時候,很常看到圖下第二種寫法,詢問結果大多都是先寫程式再寫測試,也時常聽到說寫完程式不知道該怎麼測試,這是怎麼一回事呢?是這樣的,程式有分抽象層與實例層,我們更應該把可以抽象的東西獨立,在最終實例化它,所以不要再把var 或是 數據(data)變數到處用了。

https://ithelp.ithome.com.tw/upload/images/20200929/20129187L9WNTkT9Ud.png

寫出一個好測試的程式,應該善用區域變數參數回傳值,我很常看到使用元件裡的數據(data)變數來撰寫所有的程式,這會讓你的程式過於依賴,不能複用,也不好寫測試,更好的做法應該是像圖上第一個,使用區域變數、參數與回傳值。

有任何問題歡迎下方留言,如果喜歡我的文章別忘了按讚、訂閱追蹤加分享唷!!
---我是分隔線-----------------------------------------------------------
PollyPO技術-前端設計轉前端工程師-JS踩坑雜記 30 天
喬依司-實作經典 JavaScript 30
五百億-Vue CLI + Firebase 雲端資料庫 30天打造簡易部落格及後臺管理
eien_zheng-前端小嘍嘍的Golang學習旅程_The journey of learning Golang


上一篇
Day25 你要去哪裡? - Vue Router 路由-2
下一篇
Day27 老司機快上車- Vue Event Bus 事件巴士
系列文
忍住不打牌位,只要30天VueJS帶你上A牌30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言