Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

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

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

Patrick Wang

August 14, 2017
Tweet

More Decks by Patrick Wang

Other Decks in Technology

Transcript

  1. 使⽤用 Jest 進⾏行行 Front-End Unit Test
    Patrick Wang (patw)
    2017/08/14
    線上 React 讀書會版

    View Slide

  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/

    View Slide

  3. ⼤大綱

    View Slide

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

    View Slide

  5. 前⾔言

    View Slide

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

    View Slide

  7. https://github.com/patw0929/react-intl-tel-input
    緣起:練習 & 在專案上掛⼀一些 badge 好棒棒!
    (⽽而且 Side/open source project 不會被 KPI 與組織流程綁架!)

    View Slide

  8. 趕案的⽇日常

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  14. View Slide

  15. Frameworks

    View Slide

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

    View Slide

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

    View Slide

  18. E2E Testing
    • Casper.js
    • Protractor
    • Nightwatch.js
    • CodeceptJS
    • Appium / Detox (Mobile App)
    http://reactmad-testing.surge.sh/#/5

    View Slide

  19. Jest 基本設定

    View Slide

  20. 安裝 & 設定
    jest & enable babel
    .babelrc
    現在 create-react-app 也都會幫你建好
    https://facebook.github.io/jest/docs/getting-started.html

    View Slide

  21. npm scripts
    package.json
    持續監看
    產⽣生 coverage 結果
    跑測試

    View Slide

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

    View Slide

  23. jest configuration - setupFiles
    setupFiles 中除了了預設的 polyfill 外,

    還可設定其他的內容:
    這邊是為了了 mock 掉 localStorage

    View Slide

  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.

    View Slide

  25. Enzyme

    View Slide

  26. Enzyme
    • by Airbnb
    • 封裝了了 React 的官⽅方測試⼯工具,擁有類似 jQuery 的
    選擇器 API,測試撰寫上更更⽅方便便

    View Slide

  27. Enzyme - find
    • 使⽤用 React TestUtils 選取特定⽬目標的 API:

    TestUtils.findRenderedDOMComponentWithXXXX
    • 使⽤用 Enzyme 只要 component.find(selector) 即可:

    http://airbnb.io/enzyme/docs/api/selector.html

    View Slide

  28. Enzyme
    • shallow
    • render
    • mount

    View Slide

  29. Enzyme - shallow
    • 封裝官⽅方的 shallow rendering
    • 只渲染第⼀一層,不渲染⼦子元件
    • 速度快
    • 不管 child component 的⾏行行為,測試重點只是
    component 本⾝身

    View Slide

  30. Enzyme - render
    • 類似 shallow,但使⽤用 Cheerio 引擎
    • 不只渲染⼀一層
    • API 跟 shallow 基本上⼀一致

    View Slide

  31. Enzyme - mount
    • Full rendering
    • 真實的 DOM 節點
    • 想要測試與 DOM 的互動與後續產⽣生的變化(如
    Click 後刪除了了⼀一個 list 的項⽬目)
    • 想要測試完整的⽣生命週期

    View Slide

  32. 語法與規則

    View Slide

  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

    View Slide

  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);
    });
    });

    View Slide

  35. expect
    所謂"斷⾔言",就是判斷源碼的實際執⾏行行結果與預期結果
    是否⼀一致,如果不⼀一致就拋出⼀一個錯誤。
    http://www.ruanyifeng.com/blog/2015/12/a-mocha-tutorial-of-examples.html
    expect(add(1, 1)).to.be.equal(2);

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  39. 專案使⽤用的測試檔案命名規則 (2/2)
    • 若若需定義很長的「測試⽤用資料」,建議另外建⼀一⽀支檔
    案放置,並放置在同⼀一層。再於測試檔案中 import
    進來來使⽤用。
    • 會放在 __tests__/mocks/ 底下,例例如:
    • mockNews.json
    • 可直接抓回 API 的 response 當做內容

    View Slide

  40. 範例例專案

    View Slide

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

    View Slide

  42. 各部分 Test 重點與⽅方法

    (以 react + redux 為例例)

    View Slide

  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 也可以⽤用喔!!

    View Slide

  44. Component - snapshot
    snapshot

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  48. Container
    測試重點
    1. Container 與其 Component 都有被 render 出來來
    • 需⽤用 包起來來
    2. 被 Mock 的 Component 有被 call ⼀一次
    3. 呼叫 action 後,dispatch 有被執⾏行行

    View Slide

  49. Container
    準備假資料、⽤用 Provider 包起來來、傳入 context(如果有)

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  53. Reducer
    測試重點
    1. 輸入 initial state 與 action 後,返回預期的 state
    2. 連續輸入 state 與 action 後,與 snapshots 相符

    View Slide

  54. Reducer

    View Slide

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

    View Slide

  56. snapshot ⽤用於 reducer

    View Slide

  57. snapshot ⽤用於 reducer

    View Slide

  58. Action
    測試重點
    1. 執⾏行行 action 後,返回預期的 object (type 與
    payloads)
    2. 承上,但中間經過 mock 過的 ajax

    View Slide

  59. Action

    View Slide

  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

    View Slide

  61. Action - mock ajax (2/4)

    View Slide

  62. Action - mock ajax (3/4)

    View Slide

  63. Action - mock ajax (4/4)
    把原本 ajax 的部份 mock 掉
    也可以⽤用 ES7 await/async

    View Slide

  64. 其他 jest ⼩小技巧

    View Slide

  65. jest.mock(module_path, fn) (1/2)
    • Jest 特⾊色之⼀一,讓測試專注在現在測試的模組本⾝身,
    import 的 module mock 掉,避免影響測試中的模
    組。
    • 但 Jest v15 起,automocking 預設是關掉的。(官
    ⽅方說明)

    View Slide

  66. jest.mock(module_path, fn) (2/2)

    View Slide

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

    View Slide

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

    View Slide

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

    載入 Google Analytics,只要 jest.fn() mock 起來來就好。

    View Slide

  70. jest.fn() (2/2)
    測試可以測該 mock 過的 function 是否被 call?

    被 call 的時候附帶什什麼參參數?
    在 beforeEach 中⽤用 mockFn.mockClear() 確保每次
    都重置狀狀態(傳入參參數、次數)。

    View Slide

  71. timer 相關 mock (1/3)
    針對 timer 也可以 mock,jest.useFakeTimers()
    原⽣生的⽅方法 (setTimeout, setInterval,
    clearTimeout, clearInterval) 就真的要跑那麼
    久,⽤用 Jest 快轉吧!
    https://facebook.github.io/jest/docs/timer-mocks.html#content

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  75. CI Server 的時區不⼀一樣
    加上 TZ=Asia/Taipei 指定 TimeZone

    View Slide

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

    View Slide

  77. Coverage

    View Slide

  78. Coverage
    jest 內建 coverage。我們也在 package.json 設定好 script 了了。
    會根據 package.json 中 collectCoverageFrom 設定的⽬目錄範圍計算 coverage。

    產⽣生這樣的結果:

    View Slide

  79. Coverage
    也會在 coverage/ ⽬目錄(預設)中產⽣生 HTML 版的報告:

    View Slide

  80. Codecov

    View Slide

  81. Codecov

    View Slide

  82. Travis + Coveralls
    .travis.yml

    View Slide

  83. 參參考資料

    View Slide

  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#前端測試⼯工具簡單整理理和比較

    View Slide

  85. Thanks! <(_ _)>

    View Slide