偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

使用Enzyme測試React(Native)組件

開發(fā) 開發(fā)工具
我們非常享受Enzyme為React.js應(yīng)用提供的快速組件級UI測試功能。與許多其他基于快照的測試框架不同,Enzyme允許開發(fā)者在不進(jìn)行設(shè)備渲染的情況下做測試,從而實(shí)現(xiàn)速度更快、粒度更小的測試。

一、組件化與UI測試

在組件化出現(xiàn)之前,我們不談UI的單元測試,哪怕是對于UI頁面進(jìn)行測試都是一件非常困難的事情。其實(shí)組件化并不完全是為了復(fù)用,很多情況下也恰恰是為了分治,使得我們可以分組件對UI頁面進(jìn)行開發(fā),然后分別對其進(jìn)行單元測試。

特別是當(dāng)瀏覽器中的Web應(yīng)用越來越龐大的時(shí)候,與在后端將大型單體應(yīng)用拆分成微服務(wù)架構(gòu)的***實(shí)踐一樣,前端應(yīng)用也可以被拆分成不同的頁面和特性。

[[186101]]

每個(gè)特性由一個(gè)單獨(dú)的團(tuán)隊(duì)從端到端對其負(fù)責(zé),它允許團(tuán)隊(duì)規(guī)?;亟桓赌切┠軌颡?dú)立部署和維護(hù)的服務(wù),在2016年11月期的技術(shù)雷達(dá)當(dāng)中這種方式被稱之為微前端,微前端的目標(biāo)就是允許Web應(yīng)用的特性彼此獨(dú)立,每個(gè)特性可以獨(dú)立地開發(fā)、測試和部署。

React.js作為前端框架的后起之秀,卻在2015年攜著虛擬DOM、組件化、單向數(shù)據(jù)流等利器,給前端UI構(gòu)建掀起了一波聲勢浩大的函數(shù)式新潮流。

雖說組件化不是React***提出來的,但卻是被React在前端世界里發(fā)揚(yáng)光大的,而現(xiàn)在幾乎所有的所謂現(xiàn)代化UI框架比如Angular或者Vue都已經(jīng)將組件化作為框架的立足之本。

[[186102]]

React已經(jīng)讓UI測試變得容易很多,React組件都可以被簡化為這樣一個(gè)表達(dá)式,即UI=f(data),這個(gè)純函數(shù)返回的只是一個(gè)描述UI組件應(yīng)該是什么樣子的虛擬DOM,本質(zhì)上就是一個(gè)樹形的數(shù)據(jù)結(jié)構(gòu)。給這個(gè)純函數(shù)輸入一些應(yīng)用程序的狀態(tài),就會得到相應(yīng)的UI描述的輸出,這個(gè)過程不會去直接操作實(shí)際的UI元素,也不會產(chǎn)生所謂的副作用。

二、React組件樹的測試

按理來說按照純函數(shù)這樣的思路,React組件的測試應(yīng)該很簡單。但與此同時(shí),對于(渲染出UI的)組件樹進(jìn)行測試依然存在一個(gè)問題,從下圖中可以看出,越處于上層的組件,其復(fù)雜度越高。

對于***層的子組件來說,我們可以很容易的將其進(jìn)行渲染并測試其邏輯正確與否,但對于較上層的父組件來說,就需要對其所包含的所有子組件都進(jìn)行預(yù)先渲染,甚至于最上面的組件需要渲染出整個(gè) UI 頁面的真實(shí)DOM節(jié)點(diǎn)才能對其進(jìn)行測試,這顯然是不可取的。

React組件樹

Shallow rendering lets you render a component "one level deep" and assert facts about what its render method returns, without worrying about the behavior of child components, which are not instantiated or rendered. This does not require a DOM.

淺渲染(Shallow Rendering)解決了這個(gè)問題,也就是說在我們針對某個(gè)上層組件進(jìn)行測試時(shí),可以不用渲染它的子組件,所以就不用再擔(dān)心子組件的表現(xiàn)和行為,這樣就可以只對特定組件的邏輯及其渲染輸出進(jìn)行測試了。Facebook官方提供了react-addons-test-utils可以讓我們使用淺渲染這個(gè)特性,用于測試虛擬DOM對象,即React.Component的實(shí)例。

三、使用Enzyme簡化測試代碼

我們常常會提到,測試代碼對于復(fù)雜代碼庫的可維護(hù)性至關(guān)重要,但是測試代碼本身的易于理解和編寫,以及可讀性和可維護(hù)性也同等重要。

Enzyme is a JavaScript Testing utility for React that makes it easier to assert, manipulate, and traverse your React Components' output.

而Enzyme則來自于活躍在JavaScript開源社區(qū)的Airbnb公司,是對官方測試工具庫(react-addons-test-utils)的封裝,它模擬了jQuery的API,非常直觀并且易于使用和學(xué)習(xí),提供了一些與眾不同的接口和方法來減少測試的樣板代碼,方便你判斷、操縱和遍歷React Components的輸出,并且減少了測試代碼和實(shí)現(xiàn)代碼之間的耦合。

Enzyme理論上應(yīng)該與所有TestRunner和斷言庫相兼容,已經(jīng)集成了多種測試類庫,比如Jest、Mocha&Chai、Jasmine,不過這些不是我們今天的重點(diǎn)。

對比一下兩者facebook/react-addons-test-utils vs airbnb/enzyme的API就一目了然,立見分明:

facebook/react-addons-test-utils vs airbnb/enzyme的API

四、Enzyme的三種渲染方法

1. shallow(node[, options]) => ShallowWrapper

shallow方法就是對官方的Shallow Rendering的封裝,淺渲染在將一個(gè)組件作為一個(gè)單元進(jìn)行測試的時(shí)候非常有用,可以確保你的測試不會去間接斷言子組件的行為。shallow方法只會渲染出組件的***層DOM結(jié)構(gòu),其嵌套的子組件不會被渲染出來,從而使得渲染的效率更高,單元測試的速度也會更快。

  1. import { shallow } from 'enzyme' 
  2. describe('Enzyme Shallow', () => { 
  3.   it('App should have three <Todo /> components', () => { 
  4.    const app = shallow(<App />
  5.    expect(app.find('Todo')).to.have.length(3) 
  6.   }) 

2. mount(node[, options]) => ReactWrapper

mount方法則會將React組件渲染為真實(shí)的DOM節(jié)點(diǎn),特別是在你依賴真實(shí)的DOM結(jié)構(gòu)必須存在的情況下,比如說按鈕的點(diǎn)擊事件。

完全的DOM渲染需要在全局范圍內(nèi)提供完整的DOM API,這也就意味著它必須在至少“看起來像”瀏覽器環(huán)境的環(huán)境中運(yùn)行,如果不想在瀏覽器中運(yùn)行測試,推薦使用mount的方法是依賴于一個(gè)名為jsdom的庫,它本質(zhì)上是一個(gè)完全在JavaScript中實(shí)現(xiàn)的headless瀏覽器。

  1. import { mount } from 'enzyme' 
  2. describe('Enzyme Mount', () => { 
  3.   it('should delete Todo when click button', () => { 
  4.    const app = mount(<App />
  5.    const todoLength = app.find('li').length 
  6.    app.find('button.delete').at(0).simulate('click') 
  7.    expect(app.find('li').length).to.equal(todoLength - 1) 
  8.   }) 
  9. }) 

3. render(node[, options]) => CheerioWrapper

render方法則會將React組件渲染成靜態(tài)的HTML字符串,返回的是一個(gè)Cheerio實(shí)例對象,采用的是一個(gè)第三方的HTML解析庫Cheerio,官方的解釋是「我們相信Cheerio可以非常好地處理HTML的解析和遍歷,再重復(fù)造輪子只能算是一種損失」。

  1. import { render } from 'enzyme' 
  2. describe('Enzyme Render', () => { 
  3.   it('Todo item should not have todo-done class', () => { 
  4.    const app = render(<App />
  5.    expect(app.find('.todo-done').length).to.equal(0) 
  6.    expect(app.contains(<div className="todo" />)).to.equal(true) 
  7.   }) 
  8. }) 

 

這個(gè)CheerioWrapper可以用于分析最終結(jié)果的HTML代碼結(jié)構(gòu),它的API跟shallow和mount方法的API都保持基本一致。

五、Enzyme 的 API 方法

1. find() 方法與選擇器

從前面的示例代碼中可以看到,無論哪種渲染方式所返回的wrapper都有一個(gè).find()方法,它接受一個(gè)selector參數(shù),然后返回一個(gè)類型相同的wrapper對象,里面包含了所有符合條件的子組件。在這個(gè)對象的基礎(chǔ)上,at方法則可以返回指定位置的子組件,simulate方法可以在這個(gè)組件上模擬觸發(fā)某種行為。

Enzyme中的Selectors即選擇器類似于CSS選擇器,但是只支持非常簡單的CSS選擇器,如果需要支持復(fù)雜的CSS選擇器,就需要引入react-dom模塊的findDOMNode方法,而這是官方的TestUtils都無法提供的方式。

  1. /* CSS Selector */ 
  2. wrapper.find('.foo') //class syntax 
  3. wrapper.find('input') //tag syntax 
  4. wrapper.find('#foo') //id syntax 
  5. wrapper.find('[htmlFor="foo"]') //prop syntax 

Selectors也可以是許多其他的東西,以便于在Enzyme的wrapper中輕松地指定想要查找的節(jié)點(diǎn),在下面的示例中,我們可以通過React組件構(gòu)造函數(shù)的引用找到該組件,也可以基于React的displayName來查找組件。

  1. /* Component Constructor */ 
  2. wrapper.find(ChildrenComponent) 
  3. myComponent.displayName = 'ChildrenComponent' 
  4. wrapper.find('ChildrenComponent') 
  5. /* Object Property Selector */ 
  6. const wrapper = mount
  7.   <div> 
  8.    <span foo={3} bar={false} title="baz" /> 
  9.   </div> 
  10. wrapper.find({ foo: 3 }) 
  11. wrapper.find({ bar: false }) 
  12. wrapper.find({ title: 'baz'}) 

 

如果一個(gè)組件存在于渲染樹中,其中設(shè)置了displayName并且它的***個(gè)字符為大寫字母,就能通過字符串找到它,與此同時(shí)也可以基于React組件屬性的子集來查找組件和節(jié)點(diǎn)。

2. 測試組件的交互行為

我們不但可以通過find方法查找DOM元素,還可以通過simulate方法在組件上模擬觸發(fā)某個(gè)DOM事件,比如Click,Change等等。

對于淺渲染來說,事件模擬并不會像真實(shí)環(huán)境中所預(yù)期的那樣進(jìn)行傳播,因此我們必須在一個(gè)已經(jīng)設(shè)置好了事件處理方法的實(shí)際節(jié)點(diǎn)上調(diào)用,實(shí)際上.simulate()方法將會根據(jù)模擬的事件觸發(fā)這個(gè)組件的prop。例如,.simulate('click') 實(shí)際上會獲取onClick prop并調(diào)用它。

  1. it('simulates click events', () => {  
  2.   const onButtonClick = sinon.spy() 
  3.   const wrapper = shallow
  4.    <Foo onButtonClick={onButtonClick} /> 
  5.   ) 
  6.   wrapper.find('button').simulate('click') 
  7.   expect(onButtonClick.calledOnce).to.be.true 
  8. }) 

Sinon則是一個(gè)可以用來Mock和Stub數(shù)據(jù)代碼的第三方測試工具庫,當(dāng)我們需要檢查一個(gè)組件當(dāng)中某個(gè)特定的函數(shù)是否被調(diào)用時(shí),我們可以使用sinon.spy()方法監(jiān)視所傳入該組件作為prop的onButtonClick方法,然后再通過wrapper的simulate方法模擬一個(gè)Click事件,最終驗(yàn)證這個(gè)被spy的onButtonClick函數(shù)是否被調(diào)用。

六、如何測試 React Native?

前面我們所談?wù)摰亩际侨绾螠y試使用react-dom所構(gòu)建的React組件,即最終渲染的結(jié)果是瀏覽器當(dāng)中的DOM結(jié)構(gòu),但對于React Native來說,JavaScript代碼最終會被編譯并用于調(diào)用iOS或Android上的Native代碼,因此無法再使用基于DOM的測試工具了。

[[186103]]

與此同時(shí),React Native還有特別多的Mobile環(huán)境依賴,所以在沒有真實(shí)設(shè)備的情況下很難對其運(yùn)行環(huán)境進(jìn)行模擬,特別是當(dāng)你希望在持續(xù)集成服務(wù)器(如Jenkins、Travis CI)運(yùn)行單元測試的時(shí)候。

事實(shí)上,我們可以通過欺騙React Native讓它返回常規(guī)的React組件而不是Native組件,然后就又能愉快地使用傳統(tǒng)的JavaScript測試庫來單獨(dú)測試React Native組件邏輯。最基本的mock示例代碼如下:

  1. const mockComponent = (type) => { 
  2.   return React.createClass({ 
  3.    displayName: type, 
  4.    propTypes: { 
  5.      children: React.PropTypes.node 
  6.    }, 
  7.    render() { 
  8.      return <div {...this.props}>{this.props.children}</div> 
  9.    } 
  10.   }) 
  11. RN.View = mockComponent("View") 
  12. RN.Text = mockComponent("Text") 
  13. RN.Image = mockComponent("Image") 

 

Enzyme推薦在測試環(huán)境中使用react-native-mock這個(gè)輔助庫,這是一個(gè)使用純JavaScript將全部的React Native組件進(jìn)行mock的第三方庫,只需要導(dǎo)入這個(gè)庫就可以對React Native組件進(jìn)行渲染和測試。

七、總結(jié)

我們非常享受Enzyme為React.js應(yīng)用提供的快速組件級UI測試功能。與許多其他基于快照的測試框架不同,Enzyme允許開發(fā)者在不進(jìn)行設(shè)備渲染的情況下做測試,從而實(shí)現(xiàn)速度更快、粒度更小的測試。在開發(fā)React應(yīng)用時(shí),我們經(jīng)常需要做大量的功能測試,而Enzyme可以在大規(guī)模地減少功能測試數(shù)量上做出貢獻(xiàn)。

Enzyme

【本文是51CTO專欄作者“ThoughtWorks”的原創(chuàng)稿件,微信公眾號:思特沃克,轉(zhuǎn)載請聯(lián)系原作者】

戳這里,看該作者更多好文

 

責(zé)任編輯:趙寧寧 來源: 51CTO專欄
相關(guān)推薦

2023-11-29 11:31:03

2018-06-13 16:38:33

React Nativ組件Android

2025-02-06 03:15:48

2016-08-31 17:03:20

JavascriptReact NativWeb

2016-10-13 19:01:59

React NativUbuntu

2025-04-18 16:05:39

2016-11-09 12:18:00

ui動畫javascript

2021-07-25 21:36:24

Windows操作系統(tǒng)功能

2016-08-12 08:49:46

React NativFacebookNative

2015-09-22 09:50:36

FacebookAndroid

2017-09-11 14:35:34

編輯器開發(fā)環(huán)境React

2016-08-12 13:55:06

2023-06-24 17:09:06

React前端

2024-07-08 00:00:07

2021-03-10 05:50:06

IOCReact解耦組件

2022-07-18 09:01:58

React函數(shù)組件Hooks

2017-01-11 18:44:43

React Nativ觸摸事件Android

2017-01-04 10:18:00

React NativScrollViewAndroid

2016-08-15 13:34:37

React NativiOSjs入口

2017-03-09 13:29:04

ReactNative JSPatch
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號