關於測試的一些學習建議
我們可以組合使用一些測試工具來幫助測試 JS
程式碼,一般使用 Mocha/Chai
或是 Karma/Jasmine
。而如果當你想測試 angular
的程式碼時,你會發現還有更多的測試工具。不過對於 React 應用的測試,比較推薦使用 Airbnb 團隊出品的 anzyme 來進行元件的測試,以保住元件的穩定可靠,目前使用非常廣泛;而另一種方式是使用 Facebook
的 jest 來進行測試。
可能很多同學都覺得應該選擇以上的某一個測試庫來進行測試工作,不過,你也可以將 anzyme
和 jest
結合起來一起使用。特別是在進行一些 snapshot
快照測試的時候,兩種都是互補的,它們已經是 React
應用測試中大家公認的標準庫了。
sinon 也是個非常優秀的測試輔助工具,可以幫助我們在 spy、stub、mock
等測試階段提供相應的工具輔助測試。如果對這幾個概念不太清晰,可以看看這裡。
另外,在這裡給你隆重的給你推薦一篇 A. Sharif 寫的 Some Thoughts On Testing React/Redux Applications,滿滿的乾貨分享哦。
多一些元件的單元測試,少一些整合測試
Enzyme
可以幫助我們實現元件的單元測試和整合測試。這裡我們可以通過三種方式來渲染元件:
shallow()
mount()
render()
shallow()
只能用來渲染不包含 children 的元件,mount()
則能夠渲染所有的子元件。所以單元測試的時候可以使用 shallow()
,mount()
則一般用於整合測試。整合測試往往是很容易被割裂的,因為他需要測試由一組或是多個元件樹組合的場景,所以整合測試一般維護成本是比較高的。所以我們可以多做一些小巧的單元測試,少做一些重要的整合測試。
第三種測試的方式是使用 render()
方法,具有類似 mount()
方法的功能,不過 mount()
能夠訪問到元件的生命週期方法,比如 componentDidUpdate
等。
正如這個 issue 中提出的 API differences between render and mount/shallow,可以總結出:
- 使用
shallow
開始測試用例 - 如果
componentDidMount or componentDidUpdate
等方法也需要測試,那麼使用mount
方法吧 - 如果要測試元件生命週期方法、子元件的行為等,使用
mount
方法吧 - 如果想更高效能的測試子元件,並且對元件的生命週期等方法不怎麼關注,那麼使用
render
方法吧
保證測試用例簡單、最小顆粒度
否則的話你需要為此付出很高的維護成本。
確認每個元件是否都有執行過單元測試,確認每個 props 和 callbacks 都在整合測試的時候傳遞給了對應的子元件。
為了保證元件測試用例的小顆粒度和簡單化,你需要熟悉一下 selectors
,Enzyme
提供了豐富的 selector 去深入元件樹。
另外,建議使用 sinon 來測試 callbacks 回撥函式,不要在元件中測試業務邏輯,這真不是個好注意。而是應該將業務邏輯從元件中解耦並對其進行測試。
最後,Facebook 出品的 Jest 也能在初期幫助我們更加輕量的執行測試,你可以非常簡單就設定好 snapshot test,這樣當元件的輸出改變的話測試用例會自動的報出失敗的結果,並且能夠獲取到錯誤資訊。
擁抱 TDD(測試驅動開發)
所有的人都可能會對你說:你應該按測試驅動的模式來進行開發。但是,幾乎沒幾個人會這麼,專案需求如山的積壓,上線的指令碼火急火燎,測試驅動?玩呢?!可能大部分小夥伴都是這樣的心聲。
不過,如果你能夠清晰的在 React + Redux 的應用中使用對應的測試方案對每個部分都進行測試,你就能夠非常輕鬆的實現 TDD。儘管你會發現 reducer 的測試和元件的測試是很不一樣的,但其實每種型別(reducer、component、…. )的測試模式其實都是一樣的。
就拿 reducer 的測試為例吧,一般是期望 reducer(state, action) === newState
,其實這種方式和 (input) => output
的模式是一樣的。如果你要測試 state 的不可變性的話,建議你可以使用 deep-freeze,可以看下以下示例程式碼:
1 2 3 4 5 6 7 8 9 |
import deepFreeze from 'deep-freeze' const initialState = { ... }; const action = { type: ..., payload: ... }; const expectedState = { ... }; deepFreeze(initialState); expect(reducer(initialState, action)).to.equal(expectedState); |
如果你能夠很清晰的知道如何測試應用中的每一個部分,那就最好採用 TDD。
多元件測試
關於資源載入的選擇
React
雖然是個 library
,但是它的生態圈非常的豐富,會有非常多的可擴充套件框架或類庫可以加入使用,但是千萬別太快的加入這些擴充套件方案。並且每次新加入一個模組的時候,要在團隊裡面確認每個人都是清楚瞭解的。特別是對於 Redux
本身的一些生態擴充套件,會有非常多的一些小模組,比如下面這些:
- 在大家還沒開始寫
action creators
和reducers
之前,就不要新增 redux-actions - 在大家還沒寫出第一個自己的
form
表單和表單驗證的時候,就不要加入 redux-form - 在大家還沒開始寫自己的
selectors
之前,就不要加入 reselect - 在大家還麼開始寫第一個高階元件
HOC
之前,就不要加入 recompose - …..
同時,關注一些大牛的最佳實踐,並且建立你自己的最佳實踐。不過得確保團隊中其他小夥伴也能理解。定義清晰的命名規則和目錄結構,並且在專案做一些升級的時候得把這些約定提前討論清楚。
保持持續的技術學習熱情
- 關注技術社群的新動向,比如在應用中使用 ramda.js.,看看如何在React中優雅的寫程式碼
- 學習如何使用 React Native 構建你的移動應用
- 學習使用 Electron 構建你的桌面應用
- 也許你可以關注如何使用 Mobx 來進行應用狀態管理
- React 僅僅只是 UI 層的一個 library ,你可以使用PREACT 和 inferno 等類似 React 的庫來替代,他們的體積能加輕量,渲染更加高效,也許是個不錯的選擇。
- Airbnb 的 React/JSX 規範 我也建議你抽時間看看,對於團隊一致化開發非常有幫助。同時,也可以使用 ESLint 來進行程式碼規則檢查。
結束語
全文完結,感謝你的閱讀,希望整個系列的文章對你今後的學習有所幫助。