日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > HTML >内容正文

HTML

前端如何实现网络速度测试功能_前端组件单元测试

發布時間:2025/3/15 HTML 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 前端如何实现网络速度测试功能_前端组件单元测试 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
啥?單元測試?我哪有時間寫單元測試?

從軟件質量說起

日常生活中,商品質量永遠是我們進行選擇時需要著重考慮的因素,計算機軟件也不例外。優秀的軟件應當如我們預期的一樣工作,能夠正確地處理所有功能性需求。優秀的軟件應當如我們預期一樣,持續穩定運行直到地老天荒。然而,現實生活中的軟件似乎永遠是那么脆弱不堪。Bug這個計算機行話隨著普遍存在的計算機軟件缺陷,逐漸變成了可能是被行外人最熟悉的詞匯。由此可見,保障軟件質量實在不是一件容易的事情。

在改進軟件質量這件事情上,人類付出了巨大的努力與探索。在一些最為關鍵的技術領域,比如分布式系統的一致性問題中,如 Amazon、Microsoft 等公司采用了形式化驗證的方式檢查軟件系統的正確性。例如,這篇文章介紹了 Amazon 如何利用 TLA+ 檢查并發現 DynamoDB 中若干可以導致數據丟失的設計 bug。然而在更一般的場景中,我們并不需要動用形式化驗證這種大殺器,而是采取軟件測試的方式進行。

到底軟件測試是啥?

大部分人接觸“軟件測試”這個概念的時間遠早于他們的預期。小時候的網絡游戲,第一次向廣大玩家普及了“內測”、“公測”這樣的概念,雖然可能很多人都并不能意識到這個關乎軟件測試,但這應該是大部分人第一次接觸“軟件測試”這個概念的契機。再往后,更多人是在本科階段的《軟件工程》這門課程中接觸到軟件測試。無論早期的瀑布開發模型亦或是后期的敏捷開發模型再到更現代的極限編程模型,軟件測試都是軟件開發生命周期中不可缺少的一環,書籍中都會對其進行詳細的介紹。但,到底什么是軟件測試呢?

書本上對軟件測試的正式定義形形色色,但這里我說說自己的理解。最廣義的說,我們日常每次“運行”軟件,其實就能看成一次測試;而最狹義的測試里,我們會定義軟件的規格,定義軟件的邊界條件,書寫測試用例,編寫自動化測試代碼或者以文檔形式寫出軟件操作步驟,并交于專人驗證開發人員提交的程序是否符合規格定義。但是,一般地說,驗證軟件行為是否符合需求的行為就叫做軟件測試。

由此可見,要理解軟件測試,先要理解軟件需求。

功能性需求與非功能性需求

需求定義了軟件。功能性需求和非功能性需求分別告訴開發者「做什么」和「做成什么樣」。比如對于即時通信軟件,「發送消息」、「接收消息」、「顯示歷史消息」等就屬于功能性需求,他們定義了一個一個的功能點,而「軟件崩潰率小于千分之一」,「能夠支持多平臺操作系統」等就屬于非功能性需求。軟件測試就是為了檢驗軟件是否能滿足定義的需求而進行的活動。

為什么單元測試需要開發人員來寫?

在具有一定規模的軟件開發組織中,必然有專業負責產品質量保證的QA團隊,也即通常意義上的測試團隊。他們對軟件最終出產的質量負責,他們會針對軟件發版時定格的需求,規劃測試用例,進行手動、半自動或全自動測試。還會引入混沌工程,幫助找出一些常規測試手段與使用方法下無法發現的潛在故障。甚至還會找到目標用戶,邀請他們試用軟件產品,并鼓勵他們幫助團隊尋找軟件中的潛藏缺陷。微軟就曾經以巨額獎金召集廣大用戶向其提交使用過程中遇到的缺陷。

那么,既然有如此專業的測試團隊,為什么我們還需要讓開發人員來寫單元測試呢?

單元測試能夠幫助大中型系統快速迭代

對于大中型系統,多人協作與持續改進迭代是常態。一個經過長期迭代的大中型系統中包含了海量特性,這也就使得未來的迭代往往可能牽一發而動全身。尤其是當某個新增的功能點需要變更軟件底層設計的時候,我們所做的修改很容易使得看上去相同的對外接口在一些特定條件下表現出不同的行為。具有單元測試的項目就可以在修改模塊內部實現后,對模塊對外表現的功能,尤其是需要滿足的特定邊界條件進行測試,從而很容易將隱藏其中的一些問題充分暴露出來。

單元測試能夠幫助開發人員改進軟件設計

所有的自動化軟件測試,最終都要落腳到斷言上。那么為了使得被測試的程序可以被斷言,開發人員不得不事前規劃軟件設計,使得每一個單元的關鍵執行結果都可被斷言。因此,當開發人員注意到代碼可測試性后,開發者就會對代碼中每一個被測單元的輸入與輸出都非常清晰,依賴也變得清晰,無用的依賴會自然減少,軟件設計變得凝練,可維護性增強。

什么是前端的單元

在談了測試的重要性以及單元測試為何需要開發人員編寫之后,我們來看看什么是單元。單元測試位于所有測試的最底層,粒度最小,執行速度最快,通常由開發工程師編寫并執行,那么對于前端開發來說,什么是「單元」?從目前主流的三大框架的視角看過去,前端的MVVM架構將前端應用分為了三塊主要部分:View、Model和ViewModel,我們逐一來看:

  • View層,JSX或者template,通常的表現形式為無狀態組件或者純函數式組件,給定Props的情況下一定會有相同的DOM或者VDOM被渲染出來。
  • Model層,狀態管理工具所處的位置,通常會利用Vuex、Redux、MobX、RxJS等工具進行編寫,視圖無關,通常從ViewModel中得到輸入,執行一些副作用,或者將輸出更新到ViewModel上。
  • ViewModel層,通常與View層雙向綁定,但是當View與其不能完美適配時,ViewModel層負責將數據依據View的需求進行轉化,因此該層是大量工具函數的應用之處。如各種各樣的Formatter、各種各樣的Filter等往往位于這一層。

從這里我們就能發現,前端的單元與后端不同,既有以類為單位的單元,也有以函數為單位的單元,也有以組件為單位的單元。而這三類不同領域的單元測試又各有特色,讓我們逐一來看。

測試三部曲

在具體討論View、Model與ViewModel層的測試前,先說說單元測試中三個重要的組成部分。我們可以把單元測試想象成一場考試,一個一個代碼單元就是這場考試中的考生,測試用例是考試的考題,預期結果是考試的答案。那么測試三部曲包括了考生、考題與答案,即被測代碼、測試用例與預期結果。

我個人認為,在測試三部曲中,測試用例占據了核心地位。測試用例是軟件需求的具體表現形式,它以代碼的形式具體地定義了軟件需要支持的功能,應當做出的反應,需要考慮的邊界條件。被測代碼是測試三部曲必不可少的組成部分,也是我們工作的核心成果。而預期結果跟隨測試用例,自然就會浮出水面。

View層單元測試

A JavaScript library for building user interfaces,React的主頁上如此介紹它自己,事實上也是如此。相較Vue和Angular,React確實專注于更好地進行View層的抽象,無論是提出View = f(props)的思想,還是單向數據流,都創造性地使得JavaScript構建穩定大型的富交互Web應用成為可能。我們以利用React構建的View層為例說明View層單元測試。

View層單元測試的關注點

關于View層是否需要編寫單元測試,一直有很大的爭議。

眾所周知,端應用會隨著需求不斷迭代更新,View層測試究竟測試到什么粒度是一個需要重點權衡的問題。如果測試粒度過細,往往不堪需求變更之擾,而如果測試粒度過粗,與無測試覆蓋也并無差別。

業界目前采用的實踐,是對底層組件庫如類似于Antd之類的,完全與業務無關,組成用戶界面最基本單元的這些空間進行嚴格的單元測試。以Antd為例,所有的組件位于Antd工程目錄的components文件夾下,每個組件目錄下的測試都放在__test__文件夾下,在__test__文件夾中,我們可以看到所有有關該組件的單元測試,其中值得關注的是__snapshot__這個文件夾,該文件夾中存放了組件在給定條件下的DOM結構,這也意味著Antd的組件渲染測試到DOM這一層級截止。它認為,DOM結構一致即可滿足其對于渲染穩定性的要求。假如瀏覽器的渲染方式或兼容性發生改變,對于同一份DOM渲染結果與之前的版本不同,這時Antd組件就有可能出現渲染錯誤,但是Antd的單元測試并不能發現這一點。這體現了Antd對于渲染測試的取舍與判斷。

更細粒度的測試其實也是可以做的,比如我們可以啟動一個瀏覽器,然后將渲染結果截圖保存,之后每次運行測試,同樣截圖并利用類似 Resemble.js 之類的工具進行逐像素比對,這樣測試能夠對最終渲染視覺效果負責,但是隨之而來的問題是,一像素的誤差都會導致測試告警,測試在很多情況下都處于失敗狀態,這無疑也沒有意義。因此如何取舍也是一個見仁見智的問題。

除了渲染測試之外,View層測試還要關注組件內state的變化,通常state的變化會由組件內部事件或者外部事件進行推動的,如點擊事件,表單值改變事件或者網絡請求。

基于React的View層測試需要用到的工具

Jest

Jest 是 Facebook 出品的一個測試框架,相對其他測試框架,其一大特點就是就是內置了常用的測試工具,比如自帶斷言、測試覆蓋率工具,實現了開箱即用。而作為一個面向前端的測試框架, Jest 可以利用其特有的快照測試功能,通過比對 UI 代碼生成的快照文件,實現對 React 等常見框架的自動測試。此外, Jest 的測試用例是并行執行的,而且只執行發生改變的文件所對應的測試,提升了測試速度。目前在 Github 上其 star 數已經破萬;而除了 Facebook 外,業內其他公司也開始從其它測試框架轉向 Jest ,比如 Airbnb 的嘗試 ,相信未來 Jest 的發展趨勢仍會比較迅猛。

Jest 可以通過 npm 或 yarn 進行安裝。以 npm 為例,既可用 npm install -g jest 進行全局安裝;也可以只局部安裝、并在 package.json 中指定 test 腳本:

{"scripts": {"test": "jest"} }

Jest的基本使用

表示測試用例是一個測試框架提供的最基本的 API , Jest 內部使用了 Jasmine 2 來進行測試,故其用例語法與 Jasmine 相同。test()函數來描述一個測試用例,舉個簡單的例子:

// hello.js module.exports = () => 'Hello world' // hello.test.js let hello = require('hello.js')test('should get "Hello world"', () => {expect(hello()).toBe('Hello world') // 測試成功// expect(hello()).toBe('Hello') // 測試失敗 })

其中toBe('Hello world')便是一句斷言( Jest 管它叫 “matcher” ,想了解更多 matcher 請參考文檔)。寫完了用例,運行在項目目錄下執行npm test,即可看到測試結果:

若測試失敗,會標識出失敗的斷言位置,結果如下:

Jest中,你還可以對每個測試前需要做的工作和測試后需要做的工作進行統一處理,對測試文件中所有的用例進行統一的預處理,可以使用 beforeAll() 函數;而如果想在每個用例開始前進行都預處理,則可使用 beforeEach() 函數。至于后處理,也有對應的 afterAll() 和 afterEach() 函數。

如果只是想對某幾個用例進行同樣的預處理或后處理,可以將先將這幾個用例歸為一組。使用 describe() 函數即可表示一組用例,再將上面提到的四個處理函數置于 describe() 的處理回調內,就實現了對一組用例的預處理或后處理:

describe('test testObject', () => {beforeAll(() => {// 預處理操作})test('is foo', () => {expect(testObject.foo).toBeTruthy()})test('is not bar', () => {expect(testObject.bar).toBeFalsy()})afterAll(() => {// 后處理操作}) })

我們還可以使用 jest 測試異步代碼。異步代碼的測試關鍵在于告知測試框架,待測的異步代碼如何完成。Jest提供了兩種常見的異步代碼調用方式的測試方法。

回調函數:

// asyncHello.js module.exports = (name, cb) => setTimeout(() => cb(`Hello ${name}`), 1000) // asyncHello.test.js let asyncHello = require('asyncHello.js')test('should get "Hello world"', (done) => {asyncHello('world', (result) => {expect(result).toBe('Hello world')done()}) })

jest會給測試函數注入done函數,你只需要在回調函數執行末尾調用done函數,即可告訴jest,改異步調用已經完成。

Promise:

// promiseHello.js module.exports = (name) => {return new Promise((resolve) => {setTimeout(() => resolve(`Hello ${name}`), 1000)}) } // promiseHello.test.js let promiseHello = require('promiseHello.js')it('should get "Hello world"', () => {expect.assertions(1); // 確保至少有一個斷言被調用,否則測試失敗return promiseHello('world').then((data) => {expect(data).toBe('Hello world')}) })

對于Promise形式的異步執行方式,可以直接在promise之后的then中進行斷言。

另外,jest還支持async/await的異步執行方式,與同步一樣,只需要在await后直接斷言即可。

Jest還通過集成Istanbul支持了測試覆蓋率統計??梢酝ㄟ^增加命令行參數 --coverage 實現,也可在 package.json 文件中進行更詳細的配置。

// branches.js module.exports = (name) => {if (name === 'Levon') {return `Hello Levon`} else {return `Hello ${name}`} } // branches.test.js let branches = require('../branches.js')describe('Multiple branches test', ()=> {test('should get Hello Levon', ()=> {expect(branches('Levon')).toBe('Hello Levon')});// test('should get Hello World', ()=> {// expect(branches('World')).toBe('Hello World')// }); })

運行 jest --coverage 可看到在根目錄下生成一個測試覆蓋率報告目錄 coverage ,打開其中的 index.html :

該網頁展示了代碼覆蓋率和未測試的行數,具體統計方式可以查看Istanbul的詳細說明。

如果我們去掉 branches.test.js 中的注釋,測試覆蓋率則變成100%:

react-test-renderer

Jest提供了快照測試功能,而 react-test-renderer 可以根據 React 的 Virtual DOM 結構生成一個符合 Jest 規范的快照,如此,便可以對渲染結果進行基于 DOM 的比對:

import React from 'react'; import Link from '../Link.react'; import renderer from 'react-test-renderer';it('renders correctly', () => {const tree = renderer.create(<Link page="http://www.facebook.com">Facebook</Link>).toJSON();expect(tree).toMatchSnapshot(); });

我們先構造上述測試,運行后得到下述快照文件:

exports[`renders correctly 1`] = ` <aclassName="normal"href="http://www.facebook.com"onMouseEnter={[Function]}onMouseLeave={[Function]} >Facebook </a> `;exports[`renders correctly 1`] = ` <aclassName="normal"href="http://www.facebook.com"onMouseEnter={[Function]}onMouseLeave={[Function]} >Facebook </a> `;

這個可讀的快照文件以可讀的形式展示了 React 渲染出的 DOM 結構。相比于肉眼觀察效果的 UI 測試,快照測試直接由Jest進行比對、速度更快;而且由于直接展示了 DOM 結構,也能讓我們在檢查快照的時候,快速、準確地發現問題。

Enzyme & React Testing Library

Jest 提供了單元測試最基本的一些功能:獨立的測試環境,統一的setup、teardown,斷言庫,異步測試功能,函數 mock 、stub 和 spy,測試覆蓋率統計等,但是我們的View層測試還是需要將 React 組件進行渲染,并在渲染的組件上進行一些操作的。React 官方提供了 Test Utility,而 Enzyme 和 React Testing Library 則是在官方的 Test Utility 基礎之上進行了封裝,使得測試更加方便。

Enzyme 介紹的文章較 React Testing Library 更多,但是在 React 16 出現后,尤其是 React Hooks 出現后,Enzyme采取的打補丁的適配方式有一些根本問題無法解決。React Testing Library在FAQ中談了關于Enzyme的一些看法:

What about enzyme is "bloated with complexity and features" and "encourage poor testing practices"?

Most of the damaging features have to do with encouraging testing implementation details. Primarily, these are shallow rendering, APIs which allow selecting rendered elements by component constructors, and APIs which allow you to get and interact with component instances (and their state/properties) (most of enzyme's wrapper APIs allow this).

The guiding principle for this library is:

The more your tests resemble the way your software is used, the more confidence they can give you. - 17 Feb 2018

React Testing Library的作者認為測試應當模仿用戶使用產品時進行的操作,而非對實現細節進行測試。即應當進行黑盒測試而非白盒。

官網 https://testing-library.com/docs/recipes 的 recipe 是單元測試非常不錯的指南,值得一看。這個可讀的快照文件以可讀的形式展示了 React 渲染出的 DOM 結構。相比于肉眼觀察效果的 UI 測試,快照測試直接由Jest進行比對、速度更快;而且由于直接展示了 DOM 結構,也能讓我們在檢查快照的時候,快速、準確地發現問題。

Model層單元測試

前端的Model層有一個更加廣為人知的名字:狀態管理。細說起來又是流派之爭:以單向數據流和函數式思想為基石的Redux,同樣受單向數據流影響,但又受到響應式編程啟發的MobX,FPR流派代表的Rxjs。然后由于Redux并不支持異步操作,于是又孕育而生許多異步中間件以增強Redux的功能比如redux-thunk,redux-saga,redux-observer等等。斯坦福大學iOS開發課上,教授介紹MVC時說了這么一句話:Model定義了軟件應用。那么由此可見,不同的應用下,不同的Model層解決方案應該各有其優勢與劣勢。

我們以Redux為例說明Model層測試的關注點。在Redux中我們通常會分開測試reducer和actionCreator。Reducer必是純函數,所以其測試相對容易,通常也不會有什么外部依賴出現,即使存在,由于其純函數特性,也很容易進行mock。而actionCreator相對復雜,由于使用不同的中間件,actionCreator的形式差別會很大,但是歸根究底,就是要測試其在各個流程中是否能如預期的那樣完成各個異步操作,并創建出符合預期的,最終交付給reducer的action對象。

Model層測試常見的工具除了View層也需要用到的Jest測試框架外,還需要根據工程中的Model層庫選型選擇相對應的工具,這些工具的主要目的是為了提供一些測試輔助的手段,比如Redux的測試需要創造一個假的store來使整個程序能夠運行起來。RxJS則需要模擬其復雜的異步事件流,即「彈珠測試」。

ViewModel層單元測試

我所理解的ViewModel層,更多的是一些數據接口,數據格式轉換,數據校驗等等之類的工具性質的函數。由于后端接口給我們的數據與真正頁面上展示的形式通常有較大的差異,我們需要在真正將數據給到View層之前,經過ViewModel層進行轉化。同樣的,由于用戶在頁面上進行的輸入信息有時也會不符合軟件定義,錯誤的用戶輸入會造成系統安全隱患,因此也需要在ViewModel層對用戶輸入的數據進行校驗。

由于ViewModel層的純函數性質,通常只需要Jest庫即可進行,過程一般比較簡單,在此就不贅述。

總結

以上是生活随笔為你收集整理的前端如何实现网络速度测试功能_前端组件单元测试的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。