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 full-size 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  6. 趕案的⽇日常

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  15. Jest 基本設定

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

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

    View full-size slide

  20. 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 full-size slide

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

    View full-size slide

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

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

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

    View full-size slide

  23. Enzyme
    • shallow
    • render
    • mount

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  27. 語法與規則

    View full-size slide

  28. 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 full-size slide

  29. 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 full-size slide

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

    View full-size slide

  31. 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 full-size slide

  32. 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 full-size slide

  33. 專案使⽤用的測試檔案命名規則 (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 full-size slide

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

    View full-size slide

  35. 範例例專案

    View full-size slide

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

    View full-size slide

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

    (以 react + redux 為例例)

    View full-size slide

  38. 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 full-size slide

  39. Component - snapshot
    snapshot

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  50. snapshot ⽤用於 reducer

    View full-size slide

  51. snapshot ⽤用於 reducer

    View full-size slide

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

    View full-size slide

  53. 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 full-size slide

  54. Action - mock ajax (2/4)

    View full-size slide

  55. Action - mock ajax (3/4)

    View full-size slide

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

    View full-size slide

  57. 其他 jest ⼩小技巧

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

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

    View full-size slide

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

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    產⽣生這樣的結果:

    View full-size slide

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

    View full-size slide

  72. Travis + Coveralls
    .travis.yml

    View full-size slide

  73. 參參考資料

    View full-size slide

  74. 參參考資料
    • 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 full-size slide

  75. Thanks! <(_ _)>

    View full-size slide