成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

使用Enzyme測(cè)試React(Native)組件

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

一、組件化與UI測(cè)試

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

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

[[186101]]

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

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

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

[[186102]]

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

二、React組件樹(shù)的測(cè)試

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

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

React組件樹(shù)

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

三、使用Enzyme簡(jiǎn)化測(cè)試代碼

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

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

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

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

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

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

四、Enzyme的三種渲染方法

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

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

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

完全的DOM渲染需要在全局范圍內(nèi)提供完整的DOM API,這也就意味著它必須在至少“看起來(lái)像”瀏覽器環(huán)境的環(huán)境中運(yùn)行,如果不想在瀏覽器中運(yùn)行測(cè)試,推薦使用mount的方法是依賴于一個(gè)名為jsdom的庫(kù),它本質(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方法則會(huì)將React組件渲染成靜態(tài)的HTML字符串,返回的是一個(gè)Cheerio實(shí)例對(duì)象,采用的是一個(gè)第三方的HTML解析庫(kù)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() 方法與選擇器

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

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

  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),在下面的示例中,我們可以通過(guò)React組件構(gòu)造函數(shù)的引用找到該組件,也可以基于React的displayName來(lái)查找組件。

  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ù)中,其中設(shè)置了displayName并且它的***個(gè)字符為大寫(xiě)字母,就能通過(guò)字符串找到它,與此同時(shí)也可以基于React組件屬性的子集來(lái)查找組件和節(jié)點(diǎn)。

2. 測(cè)試組件的交互行為

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

對(duì)于淺渲染來(lái)說(shuō),事件模擬并不會(huì)像真實(shí)環(huán)境中所預(yù)期的那樣進(jìn)行傳播,因此我們必須在一個(gè)已經(jīng)設(shè)置好了事件處理方法的實(shí)際節(jié)點(diǎn)上調(diào)用,實(shí)際上.simulate()方法將會(huì)根據(jù)模擬的事件觸發(fā)這個(gè)組件的prop。例如,.simulate('click') 實(shí)際上會(huì)獲取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è)可以用來(lái)Mock和Stub數(shù)據(jù)代碼的第三方測(cè)試工具庫(kù),當(dāng)我們需要檢查一個(gè)組件當(dāng)中某個(gè)特定的函數(shù)是否被調(diào)用時(shí),我們可以使用sinon.spy()方法監(jiān)視所傳入該組件作為prop的onButtonClick方法,然后再通過(guò)wrapper的simulate方法模擬一個(gè)Click事件,最終驗(yàn)證這個(gè)被spy的onButtonClick函數(shù)是否被調(diào)用。

六、如何測(cè)試 React Native?

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

[[186103]]

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

事實(shí)上,我們可以通過(guò)欺騙React Native讓它返回常規(guī)的React組件而不是Native組件,然后就又能愉快地使用傳統(tǒng)的JavaScript測(cè)試庫(kù)來(lái)單獨(dú)測(cè)試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推薦在測(cè)試環(huán)境中使用react-native-mock這個(gè)輔助庫(kù),這是一個(gè)使用純JavaScript將全部的React Native組件進(jìn)行mock的第三方庫(kù),只需要導(dǎo)入這個(gè)庫(kù)就可以對(duì)React Native組件進(jìn)行渲染和測(cè)試。

七、總結(jié)

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

Enzyme

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

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

 

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

2023-11-29 11:31:03

2018-06-13 16:38:33

React Nativ組件Android

2025-02-06 03:15:48

2025-04-18 16:05:39

2016-08-31 17:03:20

JavascriptReact NativWeb

2016-10-13 19:01:59

React NativUbuntu

2016-11-09 12:18:00

ui動(dòng)畫(huà)javascript

2021-07-25 21:36:24

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

2015-09-22 09:50:36

FacebookAndroid

2016-08-12 08:49:46

React NativFacebookNative

2017-09-11 14:35:34

編輯器開(kāi)發(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

2017-03-09 13:29:04

ReactNative JSPatch

2024-01-19 09:03:06

ReactTypeScripFlexbox
點(diǎn)贊
收藏

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

主站蜘蛛池模板: 日本中文字幕日韩精品免费 | 国产欧美一区二区三区在线看 | 国产精品久久久久久久久久久久 | 一区二区三区免费 | 色伊人网| 精品久久久久久亚洲综合网 | av在线播放一区二区 | 国产精品人人做人人爽 | 国产久 | cao在线 | 男女一区二区三区 | 黄色小视频入口 | 免费观看日韩精品 | 超级乱淫av片免费播放 | 日韩区| 青春草国产 | 美女久久| 激情小说综合网 | 日韩成人免费在线视频 | 91久久精品日日躁夜夜躁国产 | 日韩一区二区三区精品 | 2022国产精品| 日韩久久久久久久久久久 | 中国大陆高清aⅴ毛片 | 久久精品视频免费观看 | 国产精品久久久久久久久久久新郎 | 日韩在线一区视频 | 亚洲成人精选 | 国产高清久久久 | 久久精品一 | 欧美精品网站 | 日韩欧美视频在线 | 国产一区久久久 | 国产精品精品久久久 | 亚洲精品视频在线看 | 97精品一区二区 | 激情亚洲 | 久久伊人在 | 国产成人精品久久二区二区 | 夜夜草导航 | 午夜不卡一区二区 |