使用 Jest 進行 Front-End Unit Test(線上 React 讀書會版)

使用 Jest 進行 Front-End Unit Test(線上 React 讀書會版)

* 前言
* Frameworks
* Jest 基本設定
* Enzyme
* 語法與規則
* 各部分 Test 重點與方法(以 react + redux 為例)
* 其他 jest 小技巧
* Coverage

9b2c27c2123feb9b02865c44b86456d0?s=128

Patrick Wang

August 14, 2017
Tweet

Transcript

  1. 使⽤用 Jest 進⾏行行 Front-End Unit Test Patrick Wang (patw) 2017/08/14

    線上 React 讀書會版
  2. Patrick Wang a.k.a. patw, ⼩小p • Front-end Developer • GitHub:

    github.com/patw0929 • Website: patw.me • Blog: blog.patw.me • Linkedin: www.linkedin.com/in/patrickpatw/
  3. ⼤大綱

  4. • 前⾔言 • Frameworks • Jest 基本設定 • Enzyme •

    語法與規則 • 各部分 Test 重點與⽅方法(以 react + redux 為例例) • 其他 jest ⼩小技巧 • Coverage
  5. 前⾔言

  6. • 初嚐測試 • ⼯工作上的任務 • 資源、時間 • 新⼈人 • 團隊

    • 單元測試、E2E 測試
  7. https://github.com/patw0929/react-intl-tel-input 緣起:練習 & 在專案上掛⼀一些 badge 好棒棒! (⽽而且 Side/open source project

    不會被 KPI 與組織流程綁架!)
  8. 趕案的⽇日常

  9. https://www.youtube.com/watch?v=w7Myc8TP650 產品本⾝身的⽣生命週期 & 產品的品質有被重視嗎?

  10. https://www.ptt.cc/bbs/Soft_Job/M.1475060406.A.1ED.html

  11. 內部分享 -> 組隊打怪

  12. 「這個 task 是值得投注⼯工時的,因為...」

  13. https://testing.googleblog.com/2015/04/just-say-no-to-more-end-to-end-tests.html

  14. None
  15. Frameworks

  16. Frameworks • Unit Test • Jasmine • Mocha, Chai, Sinon

    • Jest • AVA
  17. Assertion Libraries http://reactmad-testing.surge.sh/#/4

  18. E2E Testing • Casper.js • Protractor • Nightwatch.js • CodeceptJS

    • Appium / Detox (Mobile App) http://reactmad-testing.surge.sh/#/5
  19. Jest 基本設定

  20. 安裝 & 設定 jest & enable babel .babelrc 現在 create-react-app

    也都會幫你建好 https://facebook.github.io/jest/docs/getting-started.html
  21. npm scripts package.json 持續監看 產⽣生 coverage 結果 跑測試

  22. jest configuration package.json 計入 coverage 的⽬目錄 在跑測試之前的環境準備設定 透過轉換幫助測試腳本讀的懂 ES7/SCSS 程式碼

    測試腳本的檔名 pattern
  23. jest configuration - setupFiles setupFiles 中除了了預設的 polyfill 外,
 還可設定其他的內容: 這邊是為了了

    mock 掉 localStorage
  24. jest configuration - transform config/jest/cssTransform.js If you want to test

    classname (CSS Modules)… e.g., styles.foobar === 'foobar' Notice that Proxy is enabled in Node.js v6.* by default; if you are not on Node v6.* yet, make sure you invoke Jest using node --harmony_proxies node_modules/.bin/jest.
  25. Enzyme

  26. Enzyme • by Airbnb • 封裝了了 React 的官⽅方測試⼯工具,擁有類似 jQuery 的

    選擇器 API,測試撰寫上更更⽅方便便
  27. Enzyme - find • 使⽤用 React TestUtils 選取特定⽬目標的 API:
 TestUtils.findRenderedDOMComponentWithXXXX

    • 使⽤用 Enzyme 只要 component.find(selector) 即可: http://airbnb.io/enzyme/docs/api/selector.html
  28. Enzyme • shallow • render • mount

  29. Enzyme - shallow • 封裝官⽅方的 shallow rendering • 只渲染第⼀一層,不渲染⼦子元件 •

    速度快 • 不管 child component 的⾏行行為,測試重點只是 component 本⾝身
  30. Enzyme - render • 類似 shallow,但使⽤用 Cheerio 引擎 • 不只渲染⼀一層

    • API 跟 shallow 基本上⼀一致
  31. Enzyme - mount • Full rendering • 真實的 DOM 節點

    • 想要測試與 DOM 的互動與後續產⽣生的變化(如 Click 後刪除了了⼀一個 list 的項⽬目) • 想要測試完整的⽣生命週期
  32. 語法與規則

  33. describe & it 測試腳本裡⾯面應該包括⼀一個或多個describe塊,每個describe塊應 該包括⼀一個或多個it塊。 describe塊稱為"測試套件"(test suite),表⽰示⼀一組相關的測試。 它是⼀一個函數,第⼀一個參參數是測試套件的名稱("加法函數的測試 "),第⼆二個參參數是⼀一個實際執⾏行行的函數。 it塊稱為"測試⽤用例例"(test

    case),表⽰示⼀一個單獨的測試,是測試的 最⼩小單位。它也是⼀一個函數,第⼀一個參參數是測試⽤用例例的名稱("1 加 1 應該等於 2"),第⼆二個參參數是⼀一個實際執⾏行行的函數。 http://www.ruanyifeng.com/blog/2015/12/a-mocha-tutorial-of-examples.html
  34. describe & it http://www.ruanyifeng.com/blog/2015/12/a-mocha-tutorial-of-examples.html import add from './add'; import {

    expect } from 'chai'; describe('加法函數的測試', function () { it('1 加 1 應該等於 2', function () { expect(add(1, 1)).to.be.equal(2); }); });
  35. expect 所謂"斷⾔言",就是判斷源碼的實際執⾏行行結果與預期結果 是否⼀一致,如果不⼀一致就拋出⼀一個錯誤。 http://www.ruanyifeng.com/blog/2015/12/a-mocha-tutorial-of-examples.html expect(add(1, 1)).to.be.equal(2);

  36. Jest 提供的 API • describe, it • xdescribe, xit -

    暫時跳過測試時使⽤用 • fit - 僅跑此段測試 • beforeEach - 在每個測試之前都執⾏行行 • afterEach - 在每個測試之後都執⾏行行 http://www.ruanyifeng.com/blog/2015/12/a-mocha-tutorial-of-examples.html https://facebook.github.io/jest/docs/api.html#content
  37. Jest 提供的 API • expect • .toBe(value) • .not •

    .toBeTruthy(), .toBeFalsy() • .toEqual(value) • .toBeCalled() • .toBeCalledWith(arg1, arg2, …) http://www.ruanyifeng.com/blog/2015/12/a-mocha-tutorial-of-examples.html https://facebook.github.io/jest/docs/expect.html#content
  38. 專案使⽤用的測試檔案命名規則 (1/2) • 欲測試的 source 同層開⼀一個 __tests__ ⽬目錄 • 檔名:{source

    檔名}.test.js • 另外,因⽬目前使⽤用 Ducks: Redux Reducer Bundles 的規範撰 寫 redux,故 reducers 與 actions 的命名規範如下: • Actions: {source 檔名}.actions.test.js • Reducers: {source 檔名}.reducer.test.js
  39. 專案使⽤用的測試檔案命名規則 (2/2) • 若若需定義很長的「測試⽤用資料」,建議另外建⼀一⽀支檔 案放置,並放置在同⼀一層。再於測試檔案中 import 進來來使⽤用。 • 會放在 __tests__/mocks/

    底下,例例如: • mockNews.json • 可直接抓回 API 的 response 當做內容
  40. 範例例專案

  41. https://github.com/patw0929/jest-example-for-study-group 試做⼀一個「前端找⼯工作」的微型專案, 並加上 unit test!

  42. 各部分 Test 重點與⽅方法 (以 react + redux 為例例)

  43. Component 測試重點 1. Snapshot 測試 (Jest v14.0 出現) • 比對產⽣生的結果是否與上次快照相符

    • https://facebook.github.io/jest/blog/2016/07/27/jest-14.html/ • https://www.youtube.com/watch?v=HAuXJVI_bUs 2. Simulate ⾏行行為測試(例例如 click 之後改變了了 state) 因此快照也要進 git 在測 reducer 也可以⽤用喔!!
  44. Component - snapshot snapshot

  45. Component - snapshot snapshot + enzyme-to-json

  46. Component - simulate - click 想測試點擊後的⾏行行為是否如預期

  47. Component - simulate - click 模擬點擊 > 觀察結果是否如預期

  48. Container 測試重點 1. Container 與其 Component 都有被 render 出來來 •

    需⽤用 <Provider> 包起來來 2. 被 Mock 的 Component 有被 call ⼀一次 3. 呼叫 action 後,dispatch 有被執⾏行行
  49. Container 準備假資料、⽤用 Provider 包起來來、傳入 context(如果有)

  50. Container ⾃自⼰己 mock createStore 這樣就可以測試 dispatch 有沒有被執⾏行行

  51. Container Component 有被 call ⼀一次 有 render 結果

  52. Container 執⾏行行 action 後,dispatch 亦有被執⾏行行

  53. Reducer 測試重點 1. 輸入 initial state 與 action 後,返回預期的 state

    2. 連續輸入 state 與 action 後,與 snapshots 相符
  54. Reducer

  55. Reducer - Snapshot test https://twitter.com/villeimmonen/status/772754403187126272

  56. snapshot ⽤用於 reducer

  57. snapshot ⽤用於 reducer

  58. Action 測試重點 1. 執⾏行行 action 後,返回預期的 object (type 與 payloads)

    2. 承上,但中間經過 mock 過的 ajax
  59. Action

  60. Action - mock ajax (1/4) • nock • mock the

    HTTP requests
 • redux-mock-store • apply the middleware to a mock store http://redux.js.org/docs/recipes/WritingTests.html#async-action-creators
  61. Action - mock ajax (2/4)

  62. Action - mock ajax (3/4)

  63. Action - mock ajax (4/4) 把原本 ajax 的部份 mock 掉

    也可以⽤用 ES7 await/async
  64. 其他 jest ⼩小技巧

  65. jest.mock(module_path, fn) (1/2) • Jest 特⾊色之⼀一,讓測試專注在現在測試的模組本⾝身, import 的 module mock

    掉,避免影響測試中的模 組。 • 但 Jest v15 起,automocking 預設是關掉的。(官 ⽅方說明)
  66. jest.mock(module_path, fn) (2/2)

  67. __mocks__ 事先準備 mocked 版本的程式碼: 可⽤用在測試與真實環境下的程式碼有所差異異的時候 ⚠ 在測試中還是記得要 jest.mock(路路徑) 哦!

  68. jest.resetModules() 確保 import/require 的 module 沒有被污染。 通常放在 beforeEach() 中:

  69. jest.fn() (1/2) 把第三⽅方或傳入的 function mock 起來來,如此僅要測試 被 call 的次數或是附帶傳入的參參數是否正確即可。 例例:在程式碼中呼叫了了

    ga/piwik 的程式碼,但測試時沒有必要
 載入 Google Analytics,只要 jest.fn() mock 起來來就好。
  70. jest.fn() (2/2) 測試可以測該 mock 過的 function 是否被 call?
 被 call

    的時候附帶什什麼參參數? 在 beforeEach 中⽤用 mockFn.mockClear() 確保每次 都重置狀狀態(傳入參參數、次數)。
  71. timer 相關 mock (1/3) 針對 timer 也可以 mock,jest.useFakeTimers() 原⽣生的⽅方法 (setTimeout,

    setInterval, clearTimeout, clearInterval) 就真的要跑那麼 久,⽤用 Jest 快轉吧! https://facebook.github.io/jest/docs/timer-mocks.html#content
  72. timer 相關 mock (2/3) https://facebook.github.io/jest/docs/timer-mocks.html#content

  73. timer 相關 mock (3/3) https://facebook.github.io/jest/docs/timer-mocks.html#content

  74. Mockdate 有時候會⽤用到 new Date(),但執⾏行行時是當下的時間。 (造成每次 snapshot 都跟上次不⼀一樣) 那就⽤用 mockdate.set(指定時間) 吧!

    https://github.com/boblauer/MockDate
  75. CI Server 的時區不⼀一樣 加上 TZ=Asia/Taipei 指定 TimeZone

  76. Async Test Async/Await Error Handling https://facebook.github.io/jest/docs/tutorial-async.html#content

  77. Coverage

  78. Coverage jest 內建 coverage。我們也在 package.json 設定好 script 了了。 會根據 package.json

    中 collectCoverageFrom 設定的⽬目錄範圍計算 coverage。
 產⽣生這樣的結果:
  79. Coverage 也會在 coverage/ ⽬目錄(預設)中產⽣生 HTML 版的報告:

  80. Codecov

  81. Codecov

  82. Travis + Coveralls .travis.yml

  83. 參參考資料

  84. 參參考資料 • Give Jest Another Go
 https://medium.com/@jrwebdev/give-jest-another-go-86ca3d00f75 • Unit Test

    Redux Container Components - Part 1
 http://www.wsbrunson.com/react/redux/test/2016/05/08/testing-redux-containers.html • React.js 101 - React 測試入⾨門教學
 https://github.com/kdchang/reactjs101/tree/master/Appendix03 • Testing React Components With Enzyme
 http://codeheaven.io/testing-react-components-with-enzyme/ • Introduction to Jest testing framework (Youtube video)
 https://www.youtube.com/watch?v=tvy0bSgwtTo • Testing Your React (and redux) Applications (Youtube video)
 https://www.youtube.com/watch?v=n49QKIzS_Ik • 前端測試⼯工具簡單整理理和比較
 https://github.com/ellisMing/introduction-angular-test#前端測試⼯工具簡單整理理和比較
  85. Thanks! <(_ _)>