<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        如何對react hooks進行單元測試的方法

        來源:懂視網 責編:小采 時間:2020-11-27 21:52:30
        文檔

        如何對react hooks進行單元測試的方法

        如何對react hooks進行單元測試的方法:寫在前面 使用 react hook 來做公司的新項目有一段時間了,大大小小的坑踩了不少。由于是公司項目,因此必須要編寫單元測試來確保業務邏輯的正確性以及重構時代碼的可維護性與穩定性,之前的項目使用的是 react@15.x 的版本,使用 enzyme 配合 je
        推薦度:
        導讀如何對react hooks進行單元測試的方法:寫在前面 使用 react hook 來做公司的新項目有一段時間了,大大小小的坑踩了不少。由于是公司項目,因此必須要編寫單元測試來確保業務邏輯的正確性以及重構時代碼的可維護性與穩定性,之前的項目使用的是 react@15.x 的版本,使用 enzyme 配合 je

        寫在前面

        使用 react hook 來做公司的新項目有一段時間了,大大小小的坑踩了不少。由于是公司項目,因此必須要編寫單元測試來確保業務邏輯的正確性以及重構時代碼的可維護性與穩定性,之前的項目使用的是 react@15.x 的版本,使用 enzyme 配合 jest 來做單元測試毫無壓力,但新項目使用的是 react@16.8 ,編寫單元測試的時候,遇到不少阻礙,因此總結此篇文章算作心得分享出來。

        配合 enzyme 來進行測試

        首先,enzyme 對于 hook 的支持程度,可以參考這個 issue,對于各個 hook 的支持程度,里面有鏈接,有說明,這里就不贅述了。我在這里想說的是,使用 enzyme 來測試 hook 在測試以及驗證方式上的一些轉變。

        測試狀態

        由于 function component 沒有實例的概念,我們無法通過類似 instance.xxx 的方式來直接對狀態進行驗證,比如:
        對于這里的 count 是無法通過 enzyme 中 wrapper.state 的 api 來訪問的,但是我們可以通過 wrapper.text 來取出 button 的文字節點,間接地測試 count 狀態,如:

        const Counter = () => {
         const [count, setCount] = useState(0)
         return <button>{count}</button>
        }
        

        測試方法

        同理,我們也無法通過 instance.methodXXX 的方式來直接獲取組件實例的方法,進而進行調用和測試,比如:

        const wrapper = mount(<Counter/>)
        expect(wrapper.find('button').text()).toBe('0')
        

        如何獲取 inc 方法的引用呢?我們可以通過 wrapper.prop 來曲線救國:

        const Counter = () => {
         const [count, setCount] = useState(0)
         const inc = useCallback(() => setCount(c => c + 1), [])
         return <button onClick={inc}>{count}</button>
        }

        另外,有些情況下,我們以返回值的方式來暴露 hook 中的一些狀態以及方法,如果是這樣的話,就更簡單了,可以通過編寫 Wrapper 組件或者直接使用下一小節提及的工具庫來進行測試。

        使用 @testing-library/react-hooks

        測試有返回值的 hook

        關于這個工具庫,在它的代碼倉庫中的 README.md 對它要解決的問題、實現原理進行了詳細的說明,有興趣的甚至可以直接看它的源碼,十分簡單。這里給出一個示例來演示如何測試上一小節最后所說的情況,比如我們有一個 hook:

        function useCounter() {
         const [count, setCount] = useState(0)
         const inc = useCallback(() => setCount(c => c + 1), [])
         const dec = useCallback(() => setCount(c => c - 1), [])
         
         return {
         count,
         inc,
         dec
         }
        }
        

        首先,我們完全可以通過上一小節的方式來對它進行測試,只需要實現一個臨時的 Wrapper,比如:

        const CounterIncWrapper = () => {
         const {count, inc} = useCounter()
         return <button onClick={inc}>{count}</button>
        }
        
        const CounterDecWrapper = () => {
         const {count, dec} = useCounter()
         return <button onClick={dec}>{count}</button>
        }
        
        

        然后單獨按照上一節提及的方式來測試 CounterIncWrapper 或者 CounterDecWrapper 就可以了,但我們會發現,這里的 Wrapper 的邏輯是很相似的,我們是否可以將它抽離為一個公用的邏輯呢?答案當然是可以的,這正是 @testing-library/react-hooks 做的,使用它我們可以這樣測試 hook ,如下:

        test('should increment counter', () => {
         const { result } = renderHook(() => useCounter())
        
         act(() => {
         result.current.inc()
         })
        
         expect(result.current.count).toBe(1)
         
         act(() => {
         result.current.dec()
         })
        
         expect(result.current.count).toBe(0)
        })
        
        

        這里的 act 是內置的工具方法,可以參考官方文檔進行了解,任何對于狀態的修改,都應該在它的回調函數中進行,不然會出現錯誤警告。

        測試有依賴項的 hook

        有些情況下,我們的 hook 會存在依賴的,比較常見的是 useContext 這個 hook ,它依賴一個 Provider 父組件,比如輕量級的狀態管理庫 unstated-next ,假設我們將上面的 hook 抽象成了一個獨立的 Container (這里會涉及 unstated-next 的 api ,但不影響理解):

        const Counter = createContainer(useCounter)

        要使用這個 Container ,我們需要這樣:

        可以發現,這里的 CounterDisplay 依賴于 Counter.Provider ,要測試 CounterDisplay ,我們通過 renderHook 的 wrapper 參數來注入父組件,比如:

        function CounterDisplay() {
         let counter = Counter.useContainer()
         return (
         <div>
         <button onClick={counter.dec}>-</button>
         <span>{counter.count}</span>
         <button onClick={counter.inc}>+</button>
         </div>
         )
        }
        
        function App() {
         return (
         <Counter.Provider>
         <CounterDisplay />
         </Counter.Provider>
         )
        }
        
        

        另外, renderHook 還支持 initialProps 參數,它代表回調函數中的參數,這里接不贅述了。

        測試副作用

        hook 中比較難搞的應該算是 useEffect ,我花了很長時間來看別人是如何對它進行單元測試的,但是并沒有得到一些有用的信息,后來我仔細想了想,其實這個問題應該這樣來想, useEffect 是用來封裝副作用的,它只用來負責副作用的運行時機,對于副作用干了什么,對于 useEffect 完全是透明的。因此我們沒有必要對它進行單元測試,而應該在副作用的實現層確保它的正確性。但我們通常會將副作用的實現與 hook 的實現耦合起來,那怎么對副作用的實現進行測試呢?這里可以分兩種情況。

        useEffect 會運行 props 中傳遞的回調函數

        這種情況相對簡單一些,只需要通過 jest.fn() 來構造一個 spy 函數,之后通過上一節的方式渲染 hook ,通過 jest 對于 spy 函數的 api 來進行驗證即可。

        useEffect 自成一體

        這種情況下,我當前是通過將副作用代碼,直接聲明在 hook 外部的方式來進行測試的,比如:

        export function updateDocumentTitle(title) {
         document.title = title
         
         return () => {
         document.title = 'default title'
         }
        }
        
        export function useDocumentTitle(title) {
         useEffect(() => updateDocumentTitle(title), [title])
        }
        
        

        這樣,只需要單獨測試 updateDocumentTitle 就好,而不需要在 useEffect 上花費功夫了。

        這里可能有的人會問,你這里無法覆蓋 title 改變時, effect 是否重新運行的場景,確實,當前我也沒有辦法解決這種問題,如果要解決,辦法還是有的,就是通過 useDocumentTitle 的參數,來傳遞 updateDocumentTitle ,但這對于代碼有很強的侵入性,我不建議這樣做,如果 hook 本身的實現方式就是這樣,那完全可以針對它編寫相關的測試用例,如果不是,也沒有必要為了寫測試用例而改寫原來的實現。

        hook 無法被測試的原因

        在對公司項目各個 hook 編寫單元測試時,發現一些 hook 非常難以測試,大體的特征如下:

      1. hook 的實現非常復雜,狀態繁多,依賴繁多
      2. hook 的實現不復雜,但外部依賴難以 mock
      3. hook 的實現自成一體,沒有入口
      4. 關于第一點,解決的方法當然是,化繁為簡,將復雜的 hook,劃分為多個簡單的 hook,使其職責更單一。對于第二點,如果外部依賴難以 mock ,我建議將它的測試用例放到集成測試階段進行實現,而不要花費過多精力在編寫單元測試的 mock 邏輯上。最后一點的解決方法詳見上一小節。

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        如何對react hooks進行單元測試的方法

        如何對react hooks進行單元測試的方法:寫在前面 使用 react hook 來做公司的新項目有一段時間了,大大小小的坑踩了不少。由于是公司項目,因此必須要編寫單元測試來確保業務邏輯的正確性以及重構時代碼的可維護性與穩定性,之前的項目使用的是 react@15.x 的版本,使用 enzyme 配合 je
        推薦度:
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 亚洲精品视频在线看| 激情五月亚洲色图| 日韩免费码中文在线观看| 国产精品成人免费综合| 久久久亚洲精品无码| 日本亚洲欧洲免费天堂午夜看片女人员 | 在线观看免费精品国产| 亚洲精品无码中文久久字幕| 四虎永久在线精品免费网址| 久久亚洲精品无码观看不卡| 一级毛片视频免费| 精品国产人成亚洲区| 中文字幕无码免费久久| 亚洲国产成人超福利久久精品| 一个人看的hd免费视频| 亚洲精品乱码久久久久久自慰| 免费在线中文日本| 亚洲?V乱码久久精品蜜桃| a级毛片免费观看在线| 国产又大又黑又粗免费视频| 男女猛烈无遮掩视频免费软件| 久久久久久国产精品免费免费| 亚洲女子高潮不断爆白浆| 亚洲av日韩片在线观看| 成全视频高清免费观看电视剧| 亚洲国产精品人久久| 成人五级毛片免费播放| 亚洲人成人77777网站不卡| 在线观看免费污视频| 巨胸喷奶水www永久免费| 久久亚洲国产成人精品性色| 我想看一级毛片免费的| 免费无遮挡无码视频在线观看| 久久精品国产亚洲香蕉| 永久免费AV无码国产网站| 一级毛片aaaaaa视频免费看| 精品亚洲aⅴ在线观看| 亚洲AV伊人久久青青草原| 曰批全过程免费视频网址| 美女黄频a美女大全免费皮| 日木av无码专区亚洲av毛片|