Vue 應用單元測試的策略與實踐 06 - 如何落地的幾點建議

本文首發於 Vue 應用單元測試的策略與實踐 06 - 如何落地的幾點建議 | 呂立青的博客javascript

歡迎關注知乎專欄 —— 前端的逆襲(凡可 JavaScript,終將 JavaScript。)前端

歡迎關注個人博客知乎GitHub掘金vue


本文的目標

  1. 在 Vue 項目中如何推進整個團隊按部就班地採起單元測試策略?逐步提升代碼質量和測試覆蓋率?
// Given
一個須要在團隊中推行測試策略的Tech Lead👨‍💻‍
// When
當他🚶閱讀本文的Vue應用測試策略落地部分
// Then
他可以在團隊中按部就班地推行測試策略,
他可以找到單元測試的反饋機制,追求技術卓越
複製代碼

Vue 應用測試策略的落地

1. 利用好「單元測試是一種政治正確」

談到如何推動單元測試的落地,首先得要有一個開始。不少公司都在推行 OKRs 或者 KPI 機制,而技術部門如何衡量技術性的績效呢?說實話,咱們都知道技術類績效其實很差用某些指標來衡量,但不少時候老闆們都會道聽途說以爲軟件質量特別重要,而後你們開始用測試覆蓋率來做爲考覈標準,先隨便定個數吧,就 80% 不錯。但咱們都知道,哪怕 100% 測試覆蓋率也沒法保證軟件質量,盲目追求高覆蓋率反而會物極必反出現問題,最終致使你們之後對單元測試痛恨至極。java

但正由於有了這樣一個開始的契機,你們纔開始有意識提升軟件質量。並且你們最開始都會以爲「單元測試是個好東西」,承認快速開發的同時,質量也很重要,這就是我所說的政治正確。既然都有了 OKR 的支持,那麼也就意味着,公司容許你們學習單元測試可能付出的成本,投入了成本固然就意味着潛在的收益。那麼如何快速得到收益,就成了下一個話題。react

2. 誘餌:從快速見效的事情作起

前文也說過,有些同窗就會在內心嘀咕:爲了達到「保障質量」的目的,不必定得經過測試呀,就算須要測試,也不必定得經過單元測試。這話在最開始的時候,確實是對的,誰都想得到好處以後才能放心投入進去,否則那些網絡騙子們爲何最開始總會給點回報看成誘餌呢?因此根據測試獎盃🏆,**使用靜態類型系統和 linter **就是咱們最初的誘餌,ESLint 可以捕獲拼寫或語法之類的基本錯誤,而且大多數狀況下 ESLint 每每都能經過 --fix 進行自動修復(配合 VSCode/WebStrom 插件食用更佳)。git

這一段時間,也就是養成一種反饋迴路,即暗示-慣常行爲-獎勵(via: 《習慣的力量》),等到你們都習慣了「出現 Lint 錯誤就自動修復」的自動反饋以後,便也就是離不開這一套自動化的工做方式。並且在這一階段,咱們爲此付出的成本基本爲 0,最開始也不必使用最嚴格的 ESLint 規則(airbnb/javascript: JavaScript Style Guide),按部就班就好。github

3. 真正理解前端數據流的好處

前文在講測試原則的時候也提到過單一職責原則(SRP),不少同窗在遺留代碼之上寫單元測試的時候,表示特別痛苦。「這都是些啥呀,輸入/輸出不明確,還各類反作用,一個函數作了七、8件事情,一個類承擔五、6種角色。」因此呢,這時候咱們要明白 Vue 和 Vuex 誕生的背景是什麼,理解它們各自要解決的問題是什麼。只有規範好各自的職責,纔可以把 UI 和數據流清晰得隔離開來。只有這樣,咱們做爲 vuex store 的使用者,纔會變得簡單,而不僅是把 vuex action 當成一個 API 的簡單 wrapper,全部數據處理邏輯所有都仍是放在 UI 組件裏面。vuex

**什麼是架構,其實架構就是把代碼放到該放的地方。**不寫代碼的架構師們固然就不會知道,也不會知道代碼寫爛以後,該如何去補測試。那可能就不僅是一種「補測試就像吃剩飯」的感受了,那隻能是一種在不明排泄物之上堆💩的體驗。編程

再多說一下 Vue 組件自己,我一直以爲 template 相比於 jsx 來講,很大的一個問題就是不利於重構,即抽取組件。滿屏的 this.xxx 就好像一個無敵的局部 global 對象同樣,處處都能用,也就致使處處都有反作用,從而根本沒法方便得抽取 function 或者放回 Vuex store。json

因此說,只有當咱們正確地使用 Vue 和 Vuex 以後,纔可以爲以後編寫單元測試提供良好的基礎。固然,這不是目的,哪怕不寫單元測試,也應該利用好前端數據流對於代碼的合理安放,遵循必定的原則就能享受該有的好處。我只是想聲明,哪些抱怨單元測試難寫的人,不是由於單元測試難寫,而是你的實現代碼實在太挫。

4. 從性價比最高的單元測試開始寫起

// production code
const computeTotalAmount = (products) => {
  return products.reduce((total, product) => total + product.price, 0); 
}

// testing code
it('should return summed up total amount 1000 when there are three products priced 200, 300, 500', () => {
  // given - 準備數據
  const products = [
    { name: 'nike', price: 200 },
    { name: 'adidas', price: 300 },
    { name: 'lining', price: 500 },
  ]

  // when - 調用被測函數
  const result = computeTotalAmount(products)

  // then - 斷言結果
  expect(result).toBe(1000)
})
複製代碼

這個測試的例子雖小,但五臟俱全。就是一個最簡單的 輸入/輸出 function,這就是最方便測試的地方,也最具測試價值,由於這都是最重要的業務數據邏輯。想想你的 Vue 項目中哪些地方會有這樣的純函數呢?

固然就是 Vuex 的 mutation。因此當咱們開始推行前端單元測試的時候,不要從 UI 組件開始,而是從 JavaScript 開始,從最簡單的 function 開始,遵循這個 given-when-then 的結構,可讓團隊寫出比較清晰的測試結構。這樣的單元測試,既易於閱讀,也易於編寫。

最大的好處,實際上是減小學習成本。大多數團隊成員其實都是從模仿開始,只有單元測試易於編寫,那麼你們纔會願意跟着開始嘗試寫。而最開始的那份單元測試,必定得是寫得標準的,得是易於閱讀的,從而纔是易於模仿的。反過來講,模仿,這也是「破窗理論」之因此流行的緣由。

5. 測試覆蓋率:每次進步一點點

只要你們開始動手寫單元測試,就成功了最難的 50%,接下來就須要你們堅持下來。借鑑於《遊戲改變世界》這本書中所提到的理論支持,咱們須要爲你們創造反饋,創造更滿意的工做和更有把握的成功。

精心設計的遊戲工做讓人以爲更有生產力,由於它感受起來更真實:反饋來得又強又快,影響明顯而生動。對不少不喜歡本身的平常工做、以爲它沒有什麼直接影響的人而言,遊戲裏的工做提供了真正的獎勵和知足感。

那麼,咱們該如何爲團隊創造遊戲裏打怪升級般的測試開發體驗呢?順便咱們能夠回答一下,該如何按部就班提高項目單元測試覆蓋率這個問題。

👆上圖的道理咱們都明白,哪怕天天只進步 1%,那麼一年 365 天的效果也是無比非凡的。咱們能夠給項目添加一個單元測試覆蓋率提高的hook,即每次push都會檢查並更新測試覆蓋率的閾值,每次提交都不能少於上一次提交,這樣咱們就能夠持續進步、持續改進,持續提升測試覆蓋率啦。

平時的工做平常,咱們還會有一個電視做爲 CI Monitor,因此咱們能夠把團隊項目的測試覆蓋率放上去,每次提交以後測試覆蓋率都會高一點點,給每位同窗一個即時的反饋,鼓勵你們堅持下去。

參考 Koleok/jest-coverage-ratchet: Uses jest coverage output to raise acceptable coverage threshold to current coverage 配置 jest 的 coverageReporters:

# jest.config.js
  coverageReporters: [
    "json-summary", "json", "lcov", "text", "clover"
  ],
  coverageThreshold: require('./package.json').jest.coverageThreshold
複製代碼

而後配置 Git hook,加到 prepush 裏面自動更新 測試覆蓋率閾值。

"coverage": "lerna run coverage && git add **/package.json && git diff-index --quiet HEAD || git commit -m \"test(unit): update coverage threshold CASABASEA-1246\" --no-verify",
    ...
    "hooks": {
      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS",
      "post-commit": "git update-index --again",
      "pre-commit": "lint-staged",
      "pre-push": "yarn lint && yarn test && yarn coverage"
    }
複製代碼

6. TDD,最好的寫單元測試的方式

在 XP 極限編程提到的反饋環中咱們能夠看出,除告終對編程之外,單元測試是咱們開發者最好的反饋工具。

既然單元測試應該由開發者,在開發軟件的同時編寫對應的單元測試。它應該是內建的,而不是後補的:即在編寫實現的同時完成單元測試,而不是寫完代碼再一次性補足。測試先行,這正是 TDD(測試驅動開發)的作法。使用 TDD 開發方法是獲得可靠單元測試的惟一途徑。

前文提到測試很難補,其實補出來的測試幾乎不可能完整覆蓋咱們對重構和質量的要求。TDD 和單元測試是全有或全無:不作 TDD,難以獲得好的單元測試;TDD 是得到可靠的單元測試的的惟一途徑。除此以外別無捷徑,想拋開 TDD 而得到一個好的單元測試是迷思,難以成功。

TDD(測試驅動開發)的步驟以下,可以時刻給予開發者反饋,從而堅持下去:

  • 沒有單元測試,不實現任何功能代碼;
  • 只編寫僅能表明一種失敗狀況的測試代碼;
  • 只編寫剛好能經過單元測試的產品代碼。

可喜可賀,全文完。

就我本身而言,寫這篇文章的同時,我也在團隊中推行 Vue 單元測試的落地,與此同時也嘗試了 Snapshot Testing 快照測試、Storybook 組件化測試、使用 Cypress 作 E2E 的 UI 測試等等。只能說,這過程並無想象中的那麼容易,質疑、埋怨、叫苦的聲音源源不斷,但每當只要有一位同窗說上一句「我好像體會到寫測試的好處了」,「這樣寫,實現代碼都變得很清晰了」,哪怕只有一位,那也就足夠了。

道不一樣不相爲謀,前途茫茫,技術卓越之路艱且險,與君共勉。

## 單元測試基礎

  • ### 單元測試與自動化的意義
  • ### 爲何選擇 Jest
  • ### Jest 的基本用法
  • ### 該如何測試異步代碼?

## Vue 單元測試

  • ### Vue 組件的渲染方式
  • ### Wrapper find() 方法與選擇器
  • ### UI 組件交互行爲的測試

## Vuex 單元測試

  • ### CQRS 與 Redux-like 架構
  • ### 如何對 Vuex 進行單元測試
  • ### Vue組件和Vuex store的交互

## Vue 應用測試策略

  • ### 單元測試的特色及其位置
  • ### 測試獎盃🏆:軟件測試的分層策略
  • ### 單元測試的F.I.R.S.T原則

## Vue 單元測試的落地

  • ### 應用測試策略落地的幾點建議

參考資料

本文是【草稿】React 應用單元測試策略的姊妹篇。除此以外,還有兩個緣由:1. 上次在FCC社區講TDD的時候說過單元測試的部分太乾不適合講,而是更適合寫成博客文章做爲技術參考;2. 公司內部已全線使用Vue技術棧做爲產品開發的前端框架,而單元測試卻因週期較緊而不得已暫且擱置。


您可能也會喜歡:

相關文章
相關標籤/搜索