使用React Native Testing庫(kù)進(jìn)行組件測(cè)試(案例詳解)

原文:https://around25.com/blog/component-testing-using-react-native-testing-library/
譯者:明月
主要思想是弄清楚該軟件的每個(gè)組件是否按照預(yù)期工作。僅當(dāng)軟件的每個(gè)單元正常工作時(shí),環(huán)境才能有效地工作并按預(yù)期運(yùn)行。
作為開(kāi)發(fā)人員,您可以進(jìn)行單元測(cè)試,也可以由獨(dú)立的測(cè)試人員執(zhí)行。
測(cè)試初學(xué)者的注意事項(xiàng):?jiǎn)卧獪y(cè)試可以是手動(dòng)的也可以是自動(dòng)的。整個(gè)過(guò)程涉及創(chuàng)建測(cè)試用例,對(duì)這些用例進(jìn)行審查,重新處理然后執(zhí)行。
單元測(cè)試作為功能實(shí)現(xiàn)。通過(guò)引用各種輸入值來(lái)檢查功能的輸出。這使調(diào)試過(guò)程變得更加容易。
整個(gè)軟件開(kāi)發(fā)過(guò)程變得敏捷:引入任何新的修改后,就可以單獨(dú)測(cè)試組件并將其集成到系統(tǒng)中,從而節(jié)省大量時(shí)間和成本。
由于可以在早期階段檢測(cè)和管理漏洞,因此減少了最后獲得煩人bug的機(jī)會(huì)。整體重構(gòu)和更新變得更加方便。
由于您已經(jīng)進(jìn)行了單元測(cè)試,可以為每個(gè)模塊及其功能提供深入的概述,因此文檔將變得不再那么繁瑣。
整個(gè)代碼成為模塊化的。這將是代碼變得可靠和可重用。
它有助于從統(tǒng)計(jì)角度衡量每個(gè)組件和整個(gè)系統(tǒng)的性能,同時(shí)還能確定組件在系統(tǒng)中覆蓋的區(qū)域。
您避免交付容易出錯(cuò)的產(chǎn)品。另外,您可以在降低復(fù)雜性的同時(shí)提高代碼質(zhì)量。
總體而言,單元測(cè)試是交付成功產(chǎn)品的最安全方法之一。
React Native測(cè)試庫(kù) 提供了簡(jiǎn)單而完整的 React Native測(cè)試實(shí)現(xiàn)程序。
https://github.com/callstack/react-native-testing-library這是用于測(cè)試React Native組件的輕量級(jí)解決方案,它在react-test-renderer之上促進(jìn)了實(shí)用方法。這將鼓勵(lì)更好的測(cè)試實(shí)踐。該庫(kù)與Jest并駕齊驅(qū),但也可以與其他測(cè)試運(yùn)行者合作。
https://snack.expo.io/59ZFgP9Dn下載后,我們需要通過(guò)執(zhí)行以下命令在仿真器或連接的設(shè)備上運(yùn)行項(xiàng)目:
Expo start在應(yīng)用程序中,我們有一個(gè)輸入字段,一個(gè)用于添加項(xiàng)目的按鈕和一個(gè)列表。該列表包含一個(gè)刪除按鈕,用于刪除列表項(xiàng)。主頁(yè)分為三個(gè)部分:
主主屏幕(Home.js)
列表組件(ItemsList.js)
添加項(xiàng)目組件(ItemAdder.js)
要執(zhí)行單元測(cè)試,我們需要將React Native測(cè)試庫(kù)安裝到我們的項(xiàng)目中。為此,我們需要在項(xiàng)目終端中運(yùn)行以下命令:
npm install --save-dev @testing-library/react-native該庫(kù)有一個(gè)react-test-renderer的peerDependencies列表。
對(duì)于測(cè)試人員,我們將在這里使用 jest。因此,我們需要安裝jest-native庫(kù)作為附加的jest匹配器。為此,我們需要在項(xiàng)目終端中運(yùn)行以下命令:
npm install --save-dev @testing-library/jest-native現(xiàn)在,我們需要配置我們的jest設(shè)置文件,即package.json文件中的模式。為此,我們?cè)?/span>package.json文件中存在的jest對(duì)象中添加以下配置行:
{"jest": {"preset": "react-native","setupFilesAfterEnv": ["@testing-library/jest-native/extend-expect"],"transformIgnorePatterns": ["node_modules/(?!(jest-)?react-native|@?react-navigation)"],"setupFiles": ["./node_modules/react-native-gesture-handler/jestSetup.js"]}}
我們已完成配置,但未執(zhí)行測(cè)試。
因此,我們?cè)谝粋€(gè)單獨(dú)的文件夾中創(chuàng)建一個(gè)新的測(cè)試文件,我們將在項(xiàng)目的./screens目錄中調(diào)用./test。在其中,我們創(chuàng)建一個(gè)名為Home.test.js的文件,該文件將包含與主屏幕有關(guān)的所有測(cè)試,并在運(yùn)行測(cè)試命令后執(zhí)行。
現(xiàn)在是時(shí)候?qū)⑺璧膸?kù)導(dǎo)入Home.test.js文件中以進(jìn)行測(cè)試了:
import React from 'react';import {render, fireEvent} from '@testing-library/react-native';import Home from '../Home';
為了測(cè)試基本的主屏幕模板,我們將主屏幕模板代碼渲染到終端中。
如果一切正確呈現(xiàn),那就太好了!沒(méi)有問(wèn)題。現(xiàn)在使用render()方法并將Home組件傳遞給它。
渲染方法將為我們提供測(cè)試主屏幕內(nèi)部組件所需的方法。
同樣,我們?cè)谶@里使用debug方法來(lái)呈現(xiàn)主屏幕模板:
test('rendering Home component', async () => {const {debug} = render(<Home/>);debug();});
"scripts": {"android": "react-native run-android","ios": "react-native run-ios","start": "react-native start","test": "jest","lint": "eslint ."}
每次我們要執(zhí)行測(cè)試時(shí),都需要在項(xiàng)目終端中運(yùn)行以下命令:
npm run test -watch因此,我們將獲得主屏幕模板的完整模板渲染:

如果發(fā)生任何錯(cuò)誤,則模板JSX元素的集成可能存在問(wèn)題,該問(wèn)題將在錯(cuò)誤消息本身中指示。
主屏幕中的輸入字段和按鈕組件是從ItemAdder組件導(dǎo)入的。
要測(cè)試TextInput和Button,我們需要為其分配testID屬性。使用這些testID道具,我們將能夠在測(cè)試配置中掌握這些元素。
<TextInputvalue={input}onChangeText={setInput}placeholder="Add Item..."style={styles.input}testID={`${testID}-input`}/><Buttoncolor="#000"testID = "input-button"title="+ ADD"style = {styles.button}onPress={() => {addItem(input);setInput('');}}/>
現(xiàn)在,我們可以使用Home.test.js文件中的getByTestId方法訪問(wèn)這些輸入和按鈕。然后我們通過(guò)提及它們的testID來(lái)初始化輸入字段和按鈕:
test('testing input and button', async () => {const {getByTestId, getByText} = render(<Home />,);const input = getByTestId('adder-input');const button = getByTestId('input-button');});
接下來(lái),我們使用從測(cè)試庫(kù)導(dǎo)入的fireEvent對(duì)象實(shí)例,應(yīng)用輸入并觸發(fā)按鈕單擊。我們可以在輸入中輸入文本值,并以此觸發(fā)按鈕的按下:
fireEvent.changeText(input, 'element');fireEvent.press(button);在這里,我們使用fireEvent類(lèi)中的changeText方法將輸入提供給我們應(yīng)用程序中的TextInput元素。我們提供的輸入值為'element'。按下功能將觸發(fā)我們應(yīng)用中的“添加”按鈕,這將使輸入顯示在列表中。
問(wèn)題是:如何觸發(fā)觸發(fā)事件后,輸入值“ element”是否已出現(xiàn)在列表中?
我們可以檢查渲染中是否存在文本值“ element”。
為此,我們可以利用render()提供的getByText方法。如果“元素”在渲染器中可用,則將其分配給元素常量。該代碼在下面的代碼片段中提供:
const element = getByText('element');現(xiàn)在,我們需要檢查元素是否存在于渲染器中。在其他情況下,我們期望element值出現(xiàn)在render中。
這使我們可以使用Expect函數(shù)中的tobeDefined方法,該方法將元素作為參數(shù)。如果存在該值,則不會(huì)發(fā)生錯(cuò)誤。否則,將發(fā)生錯(cuò)誤。
expect(element).toBeDefined();檢查以下完整的測(cè)試功能:
test('testing input and button', async () => {const {getByText, getByTestId} = render(<Home />,);const input = getByTestId('adder-input');const button = getByTestId('input-button');fireEvent.changeText(input, 'element'); fireEvent.press(button);const element = getByText('element');expect(element).toBeDefined();});
在這里,我們希望在添加輸入時(shí)定義元素并獲得此測(cè)試結(jié)果:

我們可以看到測(cè)試已經(jīng)通過(guò)。
這就是為什么我們現(xiàn)在也可以檢查多個(gè)輸入的原因。為此,我們分配了一個(gè)不同的輸入值'element1',并像之前的測(cè)試一樣進(jìn)行了所有操作。函數(shù)是這樣的:
test('testing input and button', async () => {const {getByText, getByTestId} = render(<Home />,);const input = getByTestId('adder-input');const button = getByTestId('input-button');fireEvent.changeText(input, 'element');fireEvent.press(button);const element = getByText('element');expect(element).toBeDefined();fireEvent.changeText(input, 'element1');fireEvent.press(button);const element1 = getByText('element1');expect(element1).toBeDefined();});
如果運(yùn)行測(cè)試命令,則會(huì)得到以下結(jié)果:

在應(yīng)用程序演示中,您會(huì)注意到,當(dāng)我們將項(xiàng)目添加到列表中時(shí),我們還會(huì)獲得一個(gè)刪除按鈕。
當(dāng)我們按下它時(shí),該項(xiàng)目消失。要測(cè)試按鈕,我們需要將testID屬性分配給ItemList.js文件中的delete Button組件:
<Buttontitle="Delete"onPress={() => deleteItem(value)}color="#f12"testID="delete-list-item"/>
現(xiàn)在在Home.test.js中,我們需要?jiǎng)?chuàng)建一個(gè)稱為“ testing delete”的新測(cè)試函數(shù)。
要測(cè)試刪除按鈕,首先我們必須在列表中有一個(gè)項(xiàng)目。
因此,我們將使用與以前相同的編碼實(shí)現(xiàn)來(lái)輸入項(xiàng)目,并檢查其渲染。然后,我們使用getAllByTestID方法,該方法將每個(gè)元素以及在其中定義的特定testID定義為數(shù)組。
現(xiàn)在,將數(shù)組分配給deleteButton常量:我們像以前一樣使用fireEvent類(lèi)中的press方法觸發(fā)按鈕。但是,由于我們僅刪除列表的第一項(xiàng),因此我們還需要分配數(shù)組標(biāo)識(shí)符。這將導(dǎo)致列表中的第一項(xiàng)被刪除。
因此,我們使用queryByText檢查該第一項(xiàng)在渲染中是否可用。然后,通過(guò)應(yīng)用toBeNull從方法期望的功能,我們可以檢查數(shù)組的第一個(gè)項(xiàng)目是否可用或者不渲染。在這里獲取功能:
test('testing delete', async () => {const {getByText, getByTestId, getAllByTestId, queryByText} = render(<Home />,);const input = getByTestId('adder-input');const button = getByTestId('input-button');fireEvent.changeText(input, 'element');fireEvent.press(button);const element = getByText('element');expect(element).toBeDefined();const deleteButton = getAllByTestId('delete-list-item');fireEvent.press(deleteButton[0]);expect(queryByText('element')).toBeNull();});
我們?cè)谶@里所做的是,我們使用tobeNull方法將'element'值添加到列表中,然后將其刪除并檢查是否刪除了'element' 。
如果答案是正確的,則該元素將被刪除,并且刪除功能將起作用。測(cè)試也應(yīng)該成功。現(xiàn)在,如果運(yùn)行測(cè)試,我們將得到以下結(jié)果:

如我們所見(jiàn),我們對(duì)刪除按鈕的測(cè)試也成功。
現(xiàn)在,對(duì)于下一個(gè)測(cè)試,我們?cè)谳斎胫挡螕簟疤砑印卑粹o后檢查列表項(xiàng)是否可用。
test('testing list items', async () => {const {getByText, getByTestId} = render(<Home />,);const input = getByTestId('adder-input');const button = getByTestId('input-button');fireEvent.changeText(input, 'element');fireEvent.press(button);const element = getByText('element');expect(element).toBeDefined();fireEvent.changeText(input, 'element1');fireEvent.press(button);const element1 = getByText('element1');expect(element1).toBeDefined();const listElements = getByTestId("list");expect(listElements).toContainElement(element);});
所有步驟,不同的類(lèi)似,我們使用toContainElement從期望函數(shù)來(lái)檢查我們?cè)诹斜碇休斎胩囟ǖ漠a(chǎn)品存在。因此,我們應(yīng)該得到以下結(jié)果:

通過(guò)準(zhǔn)備不同的測(cè)試功能并分配測(cè)試ID來(lái)渲染元素,我們可以測(cè)試其他組件。
哇,很長(zhǎng)的一段路程。讓我們快速回顧一下我們學(xué)到的東西:
什么是單元測(cè)試
為什么它是必不可少的
如何使用React Native Testing庫(kù)在React Native生態(tài)系統(tǒng)中執(zhí)行它。
最重要的一點(diǎn)是:通過(guò)基于組件渲染編寫(xiě)這些類(lèi)型的測(cè)試,我們可以驗(yàn)證React Native應(yīng)用程序的各個(gè)組件。如果發(fā)生任何錯(cuò)誤,這將有助于優(yōu)化應(yīng)用程序。
測(cè)試庫(kù)提供了其他API和方法,您可以自由探索。面臨的挑戰(zhàn)是為各個(gè)組件設(shè)計(jì)自己的測(cè)試。您甚至可以先創(chuàng)建一個(gè)組件,然后按上述步驟對(duì)其進(jìn)行測(cè)試,然后再將其集成到核心應(yīng)用中。這稱為測(cè)試驅(qū)動(dòng)開(kāi)發(fā)。我們僅用幾行代碼即可執(zhí)行測(cè)試的簡(jiǎn)單性令人驚嘆。
最后希望您能夠使用 React Native Testing 庫(kù)在React Native中掌握基于組件的基本測(cè)試方法。
以上對(duì)單元測(cè)試的原理進(jìn)行了詳細(xì)的闡述,并通過(guò) React Native Testing 庫(kù)結(jié)合具體的案例進(jìn)行了詳細(xì)的代碼輸出 ,如果您認(rèn)為對(duì)您有幫助,請(qǐng)記得 點(diǎn)贊、留言、分享和收藏 哦~~
最后
面試交流群持續(xù)開(kāi)放,分享了近 許多 個(gè)面經(jīng)。
加我微信: DayDay2021,備注面試,拉你進(jìn)群。我是 TianTian,我們下篇見(jiàn)~
2021-05-28
2021-05-26
在看點(diǎn)這里






