国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

目錄
開始進(jìn)行React 測試
選項(xiàng)1:單元測試
選項(xiàng)2:集成測試
那麼,什麼需要單元測試?
其他好處
清晰的waitFor 塊
行內(nèi)it 註釋
團(tuán)隊(duì)的後續(xù)步驟
首頁 web前端 css教學(xué) 反應(yīng)集成測試:覆蓋範(fàn)圍更大,測試較少

反應(yīng)集成測試:覆蓋範(fàn)圍更大,測試較少

Apr 07, 2025 am 09:20 AM

React Integration Testing: Greater Coverage, Fewer Tests

對於像使用React 構(gòu)建的交互式網(wǎng)站,集成測試是自然而然的選擇。它們驗(yàn)證用戶與應(yīng)用程序的交互方式,而無需端到端測試的額外開銷。

本文通過一個(gè)練習(xí)來闡述,該練習(xí)從一個(gè)簡單的網(wǎng)站開始,使用單元測試和集成測試驗(yàn)證行為,並演示集成測試如何通過更少的代碼行實(shí)現(xiàn)更大的價(jià)值。本文內(nèi)容假設(shè)您熟悉React 和JavaScript 中的測試。熟悉Jest 和React Testing Library 會有所幫助,但不是必需的。

測試分為三種類型:

  • 單元測試獨(dú)立驗(yàn)證一段代碼。它們易於編寫,但可能會忽略大局。
  • 端到端測試(E2E) 使用自動(dòng)化框架(例如Cypress 或Selenium)像用戶一樣與您的網(wǎng)站交互:加載頁面、填寫表單、點(diǎn)擊按鈕等。它們通常編寫和運(yùn)行速度較慢,但與真實(shí)的用戶體驗(yàn)非常接近。
  • 集成測試介於兩者之間。它們驗(yàn)證應(yīng)用程序的多個(gè)單元如何協(xié)同工作,但比E2E 測試更輕量級。例如,Jest 自帶一些內(nèi)置實(shí)用程序來促進(jìn)集成測試;Jest 在後臺使用jsdom 來模擬常見的瀏覽器API,其開銷小於自動(dòng)化,並且其強(qiáng)大的模擬工具可以模擬外部API 調(diào)用。

另一個(gè)需要注意的地方:在React 應(yīng)用程序中,單元測試和集成測試的編寫方式相同,使用的工具也相同。

開始進(jìn)行React 測試

我創(chuàng)建了一個(gè)簡單的React 應(yīng)用程序(可在GitHub 上找到),其中包含一個(gè)登錄表單。我將其連接到reqres.in,這是一個(gè)我發(fā)現(xiàn)用於測試前端項(xiàng)目的方便的API。

您可以成功登錄:

…或者遇到來自API 的錯(cuò)誤消息:

代碼結(jié)構(gòu)如下:

 <code>LoginModule/ ├── components/ │ ├── Login.js // 渲染LoginForm、錯(cuò)誤消息和登錄確認(rèn)│ └── LoginForm.js // 渲染登錄表單字段和按鈕├── hooks/ │ └── useLogin.js // 連接到API 并管理狀態(tài)└── index.js // 將所有內(nèi)容整合在一起</code>

選項(xiàng)1:單元測試

如果您像我一樣喜歡編寫測試——也許戴著耳機(jī),在Spotify 上播放著不錯(cuò)的音樂——那麼您可能會忍不住為每個(gè)文件編寫單元測試。

即使您不是測試愛好者,您也可能正在參與一個(gè)“試圖做好測試”的項(xiàng)目,但沒有明確的策略,測試方法是“我想每個(gè)文件都應(yīng)該有自己的測試?”

這看起來像這樣(為了清晰起見,我在測試文件名中添加了unit):

 <code>LoginModule/ ├── components/ │  ├── Login.js │  ├── Login.unit.test.js │  ├── LoginForm.js │  └── LoginForm.unit.test.js ├── hooks/ │  ├── useLogin.js │  └── useLogin.unit.test.js ├── index.js └── index.unit.test.js</code>

我在GitHub 上完成了添加所有這些單元測試的練習(xí),並創(chuàng)建了一個(gè)test:coverage:unit 腳本以生成覆蓋率報(bào)告(Jest 的內(nèi)置功能)。我們可以通過四個(gè)單元測試文件實(shí)現(xiàn)100% 的覆蓋率:

100% 的覆蓋率通常是過度的,但對於如此簡單的代碼庫來說是可以實(shí)現(xiàn)的。

讓我們深入研究為onLogin React hook 創(chuàng)建的單元測試之一。如果您不熟悉React hook 或如何測試它們,請不要擔(dān)心。

 test('successful login flow', async () => {
 // 模擬成功的API 響應(yīng) jest
  .spyOn(window, 'fetch')
  .mockResolvedValue({ json: () => ({ token: '123' }) });

 const { result, waitForNextUpdate } = renderHook(() => useLogin());

 act(() => {
  result.current.onSubmit({
   email: '[email protected]',
   password: 'password',
  });
 });

 // 將狀態(tài)設(shè)置為pending
 expect(result.current.state).toEqual({
  status: 'pending',
  user: null,
  error: null,
 });

 await waitForNextUpdate();

 // 將狀態(tài)設(shè)置為resolved,存儲電子郵件地址 expect(result.current.state).toEqual({
  status: 'resolved',
  user: {
   email: '[email protected]',
  },
  error: null,
 });
});

這個(gè)測試寫起來很有趣(因?yàn)镽eact Hooks Testing Library 使測試hook 變得輕而易舉),但它有一些問題。

首先,測試驗(yàn)證內(nèi)部狀態(tài)從'pending' 更改為'resolved';此實(shí)現(xiàn)細(xì)節(jié)不會向用戶公開,因此,可能不是要測試的好東西。如果我們重構(gòu)應(yīng)用程序,我們將不得不更新此測試,即使從用戶的角度來看沒有任何變化。

此外,作為單元測試,這只是其中一部分。如果我們想驗(yàn)證登錄流程的其他功能,例如提交按鈕文本更改為“加載中”,我們將不得不在不同的測試文件中進(jìn)行操作。

選項(xiàng)2:集成測試

讓我們考慮添加一個(gè)集成測試來驗(yàn)證此流程的替代方法:

 <code>LoginModule/ ├── components/ │  ├── Login.js │  └── LoginForm.js ├── hooks/ │  └── useLogin.js ├── index.js └── index.integration.test.js</code>

我實(shí)現(xiàn)了這個(gè)測試和一個(gè)test:coverage:integration 腳本以生成覆蓋率報(bào)告。就像單元測試一樣,我們可以達(dá)到100% 的覆蓋率,但這次都在一個(gè)文件中,並且需要的代碼行更少。

以下是涵蓋成功登錄流程的集成測試:

 test('successful login', async () => {
  jest
    .spyOn(window, 'fetch')
    .mockResolvedValue({ json: () => ({ token: '123' }) });

  render(<loginmodule></loginmodule> );

  const emailField = screen.getByRole('textbox', { name: 'Email' });
  const passwordField = screen.getByLabelText('Password');
  const button = screen.getByRole('button');

  // 填寫並提交表單fireEvent.change(emailField, { target: { value: '[email protected]' } });
  fireEvent.change(passwordField, { target: { value: 'password' } });
  fireEvent.click(button);

  // 它設(shè)置加載狀態(tài)expect(button).toBeDisabled();
  expect(button).toHaveTextContent('Loading...');

  await waitFor(() => {
    // 它隱藏表單元素expect(button).not.toBeInTheDocument();
    expect(emailField).not.toBeInTheDocument();
    expect(passwordField).not.toBeInTheDocument();

    // 它顯示成功文本和電子郵件地址const loggedInText = screen.getByText('Logged in as');
    expect(loggedInText).toBeInTheDocument();
    const emailAddressText = screen.getByText('[email protected]');
    expect(emailAddressText).toBeInTheDocument();
  });
});

我真的很喜歡這個(gè)測試,因?yàn)樗鼜挠脩舻慕嵌闰?yàn)證了整個(gè)登錄流程:表單、加載狀態(tài)和成功確認(rèn)消息。集成測試非常適合React 應(yīng)用程序,正是因?yàn)檫@種用例;用戶體驗(yàn)是我們想要測試的內(nèi)容,而這幾乎總是涉及多個(gè)不同的代碼片段協(xié)同工作

此測試不了解使預(yù)期行為起作用的組件或hook,這很好。只要用戶體驗(yàn)保持不變,我們就可以重寫和重構(gòu)這些實(shí)現(xiàn)細(xì)節(jié)而不會破壞測試。

我不會深入研究登錄流程的初始狀態(tài)和錯(cuò)誤處理的其他集成測試,但我鼓勵(lì)您在GitHub 上查看它們。

那麼,什麼需要單元測試?

與其考慮單元測試與集成測試,不如讓我們退一步,考慮一下我們?nèi)绾螞Q定首先需要測試什麼。需要測試LoginModule,因?yàn)樗且粋€(gè)我們希望使用者(應(yīng)用程序中的其他文件)能夠放心地使用的實(shí)體。

另一方面,不需要測試onLogin hook,因?yàn)樗皇荓oginModule 的實(shí)現(xiàn)細(xì)節(jié)。但是,如果我們的需求發(fā)生變化,並且onLogin 在其他地方有用例,那麼我們將需要添加我們自己的(單元)測試來驗(yàn)證其作為可重用實(shí)用程序的功能。 (我們也需要移動(dòng)該文件,因?yàn)樗辉偬囟禠oginModule 了。)

單元測試仍然有很多用例,例如需要驗(yàn)證可重用選擇器、hook 和普通函數(shù)。在開發(fā)代碼時(shí),您可能還會發(fā)現(xiàn)使用單元測試進(jìn)行測試驅(qū)動(dòng)開發(fā)很有幫助,即使您稍後將該邏輯向上移動(dòng)到集成測試。

此外,單元測試在針對多個(gè)輸入和用例進(jìn)行詳盡測試方面做得很好。例如,如果我的表單需要針對各種場景(例如無效電子郵件、缺少密碼、密碼過短)顯示內(nèi)聯(lián)驗(yàn)證,我將在集成測試中涵蓋一個(gè)代表性案例,然後在單元測試中深入研究具體案例。

其他好處

既然我們在這裡,我想談?wù)勔恍椭业募蓽y試保持清晰和有序的語法技巧。

清晰的waitFor 塊

我們的測試需要考慮LoginModule 的加載狀態(tài)和成功狀態(tài)之間的延遲:

 const button = screen.getByRole('button');
fireEvent.click(button);

expect(button).not.toBeInTheDocument(); // 太快了,按鈕還在!

我們可以使用DOM Testing Library 的waitFor 輔助函數(shù)來做到這一點(diǎn):

 const button = screen.getByRole('button');
fireEvent.click(button);

await waitFor(() => {
 expect(button).not.toBeInTheDocument(); // 啊,好多了});

但是,如果我們還想測試其他一些項(xiàng)目呢?網(wǎng)上沒有很多關(guān)於如何處理此問題的好的示例,並且在過去的項(xiàng)目中,我已經(jīng)將其他項(xiàng)目放在waitFor 之外:

 // 等待按鈕await waitFor(() => {
 expect(button).not.toBeInTheDocument();
});

// 然後測試確認(rèn)消息const confirmationText = getByText('Logged in as [email protected]');
expect(confirmationText).toBeInTheDocument();

這有效,但我不喜歡它,因?yàn)樗拱粹o條件看起來很特殊,即使我們可以輕鬆地切換這些語句的順序:

 // 等待確認(rèn)消息await waitFor(() => {
 const confirmationText = getByText('Logged in as [email protected]');
 expect(confirmationText).toBeInTheDocument();
});

// 然後測試按鈕expect(button).not.toBeInTheDocument();

在我看來,將與相同更新相關(guān)的所有內(nèi)容一起分組到waitFor 回調(diào)中要好得多:

 await waitFor(() => {
 expect(button).not.toBeInTheDocument();

 const confirmationText = screen.getByText('Logged in as [email protected]');
 expect(confirmationText).toBeInTheDocument();
});

對於像這樣的簡單斷言,我真的很喜歡這種技術(shù),但在某些情況下,它可能會減慢測試速度,等待在waitFor 之外立即發(fā)生的失敗。有關(guān)此示例,請參閱React Testing Library 常用錯(cuò)誤中的“在單個(gè)waitFor 回調(diào)中有多個(gè)斷言”。

對於包含幾個(gè)步驟的測試,我們可以連續(xù)使用多個(gè)waitFor 塊:

 const button = screen.getByRole('button');
const emailField = screen.getByRole('textbox', { name: 'Email' });

// 填寫表單fireEvent.change(emailField, { target: { value: '[email protected]' } });

await waitFor(() => {
 // 檢查按鈕是否已啟用 expect(button).not.toBeDisabled();
  expect(button).toHaveTextContent('Submit');
});

// 提交表單fireEvent.click(button);

await waitFor(() => {
 // 檢查按鈕是否不再存在 expect(button).not.toBeInTheDocument();
});

如果您只等待一個(gè)項(xiàng)目出現(xiàn),則可以使用findBy 查詢代替。它在後臺使用waitFor。

行內(nèi)it 註釋

另一個(gè)測試最佳實(shí)踐是編寫更少、更長的測試;這使您可以將測試用例與重要的用戶流程關(guān)聯(lián)起來,同時(shí)使測試保持隔離,以避免意外行為。我贊成這種方法,但它在保持代碼組織和記錄所需行為方面可能會帶來挑戰(zhàn)。我們需要未來的開發(fā)人員能夠返回測試並了解它在做什麼,為什麼它會失敗等等。

例如,假設(shè)這些期望之一開始失?。?/p>

 it('handles a successful login flow', async () => {
 // 為清晰起見隱藏測試的開頭?
  expect(button).toBeDisabled();
  expect(button).toHaveTextContent('Loading...');
?
 await waitFor(() => {
  expect(button).not.toBeInTheDocument();
  expect(emailField).not.toBeInTheDocument();
  expect(passwordField).not.toBeInTheDocument();
?
  const confirmationText = screen.getByText('Logged in as [email protected]');
  expect(confirmationText).toBeInTheDocument();
 });
});

查看此內(nèi)容的開發(fā)人員無法輕鬆確定正在測試的內(nèi)容,並且可能難以確定失敗是錯(cuò)誤(這意味著我們應(yīng)該修復(fù)代碼)還是行為更改(這意味著我們應(yīng)該修復(fù)測試)。

我最喜歡的解決方案是使用每個(gè)測試的鮮為人知的測試語法,並添加描述正在測試的每個(gè)關(guān)鍵行為的行內(nèi)it 樣式註釋:

 test('successful login', async () => {
 // 為清晰起見隱藏測試的開頭?
 // 它設(shè)置加載狀態(tài) expect(button).toBeDisabled();
  expect(button).toHaveTextContent('Loading...');
?
 await waitFor(() => {
  // 它隱藏表單元素  expect(button).not.toBeInTheDocument();
  expect(emailField).not.toBeInTheDocument();
  expect(passwordField).not.toBeInTheDocument();
?
  // 它顯示成功文本和電子郵件地址  const confirmationText = screen.getByText('Logged in as [email protected]');
  expect(confirmationText).toBeInTheDocument();
 });
});

這些註釋不會神奇地與Jest 集成,因此如果您遇到失敗,失敗的測試名稱將對應(yīng)於您傳遞給測試標(biāo)籤的參數(shù),在本例中為“successful login”。但是,Jest 的錯(cuò)誤消息包含周圍的代碼,因此這些it 註釋仍然有助於識別失敗的行為。當(dāng)我從一個(gè)期望中刪除not 時(shí),我收到了以下錯(cuò)誤消息:

為了獲得更明確的錯(cuò)誤,有一個(gè)名為jest-expect-message 的包允許您為每個(gè)期望定義錯(cuò)誤消息:

 expect(button, 'button is still in document').not.toBeInTheDocument();

一些開發(fā)人員更喜歡這種方法,但我發(fā)現(xiàn)它在大多數(shù)情況下有點(diǎn)granular 了,因?yàn)閱蝹€(gè)it 通常涉及多個(gè)期望。

團(tuán)隊(duì)的後續(xù)步驟

有時(shí)我希望我們可以為人類製定linter 規(guī)則。如果是這樣,我們可以為我們的團(tuán)隊(duì)設(shè)置一個(gè)prefer-integration-tests 規(guī)則,然後就結(jié)束了。

但是,唉,我們需要找到一個(gè)更類似的解決方案來鼓勵(lì)開發(fā)人員在某些情況下選擇集成測試,例如我們前面介紹的LoginModule 示例。像大多數(shù)事情一樣,這歸結(jié)於團(tuán)隊(duì)討論您的測試策略,就對項(xiàng)目有意義的內(nèi)容達(dá)成一致,並且——希望——在ADR 中記錄它。

在製定測試計(jì)劃時(shí),我們應(yīng)該避免一種會迫使開發(fā)人員為每個(gè)文件編寫測試的文化。開發(fā)人員需要能夠放心地做出明智的測試決策,而不必?fù)?dān)心他們“測試不足”。 Jest 的覆蓋率報(bào)告可以通過提供一個(gè)健全性檢查來幫助解決這個(gè)問題,即使測試在集成級別上進(jìn)行了合併。

我仍然不認(rèn)為自己是集成測試專家,但是進(jìn)行這項(xiàng)練習(xí)幫助我分解了一個(gè)集成測試比單元測試提供更大價(jià)值的用例。我希望與您的團(tuán)隊(duì)分享這一點(diǎn),或者在您的代碼庫上進(jìn)行類似的練習(xí),將有助於指導(dǎo)您將集成測試納入您的工作流程。

以上是反應(yīng)集成測試:覆蓋範(fàn)圍更大,測試較少的詳細(xì)內(nèi)容。更多資訊請關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本網(wǎng)站聲明
本文內(nèi)容由網(wǎng)友自願(yuàn)投稿,版權(quán)歸原作者所有。本站不承擔(dān)相應(yīng)的法律責(zé)任。如發(fā)現(xiàn)涉嫌抄襲或侵權(quán)的內(nèi)容,請聯(lián)絡(luò)admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅(qū)動(dòng)的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費(fèi)的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強(qiáng)大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

什麼是'渲染障礙CSS”? 什麼是'渲染障礙CSS”? Jun 24, 2025 am 12:42 AM

CSS會阻塞頁面渲染是因?yàn)闉g覽器默認(rèn)將內(nèi)聯(lián)和外部CSS視為關(guān)鍵資源,尤其是使用引入的樣式表、頭部大量內(nèi)聯(lián)CSS以及未優(yōu)化的媒體查詢樣式。 1.提取關(guān)鍵CSS並內(nèi)嵌至HTML;2.延遲加載非關(guān)鍵CSS通過JavaScript;3.使用media屬性優(yōu)化加載如打印樣式;4.壓縮合併CSS減少請求。建議使用工具提取關(guān)鍵CSS,結(jié)合rel="preload"異步加載,合理使用media延遲加載,避免過度拆分與復(fù)雜腳本控制。

外部與內(nèi)部CSS:最好的方法是什麼? 外部與內(nèi)部CSS:最好的方法是什麼? Jun 20, 2025 am 12:45 AM

thebestapphachforcssdepprodsontheproject'sspefificneeds.forlargerprojects,externalcsSissBetterDuoSmaintoMaintainability andReusability; forsMallerProjectsorsingle-pageApplications,InternaltCsmightBemoresobleable.InternalCsmightBemorese.it.it'sclucialtobalancepopryseceneceenceprodrenceprodrenceNeed

我的CSS必須在較低的情況下嗎? 我的CSS必須在較低的情況下嗎? Jun 19, 2025 am 12:29 AM

否,CSSDOESNOTHAVETOBEINLOWERCASE.CHOMENDENS,使用flowercaseisrecommondendendending:1)一致性和可讀性,2)避免使用促進(jìn)性技術(shù),3)潛在的Performent FormanceBenefits,以及4)RightCollaboraboraboraboraboraboraboraboraboraboraboraboraboraboraboraboraborationWithInteams。

CSS案例靈敏度:了解重要的 CSS案例靈敏度:了解重要的 Jun 20, 2025 am 12:09 AM

cssismostlycaseminemintiment,buturlsandfontfamilynamesarecase敏感。 1)屬性和valueslikeColor:紅色; prenotcase-sensive.2)urlsmustmustmatchtheserver'server'scase,例如

什麼是AutoPrefixer,它如何工作? 什麼是AutoPrefixer,它如何工作? Jul 02, 2025 am 01:15 AM

Autoprefixer是一個(gè)根據(jù)目標(biāo)瀏覽器範(fàn)圍自動(dòng)為CSS屬性添加廠商前綴的工具。 1.它解決了手動(dòng)維護(hù)前綴易出錯(cuò)的問題;2.通過PostCSS插件形式工作,解析CSS、分析需加前綴的屬性、依配置生成代碼;3.使用步驟包括安裝插件、設(shè)置browserslist、在構(gòu)建流程中啟用;4.注意事項(xiàng)有不手動(dòng)加前綴、保持配置更新、非所有屬性都加前綴、建議配合預(yù)處理器使用。

什麼是CSS計(jì)數(shù)器? 什麼是CSS計(jì)數(shù)器? Jun 19, 2025 am 12:34 AM

csscounterscanautomationallymentermentermentections和lists.1)usecounter-ensettoInitializize,反插入式發(fā)芽,andcounter()orcounters()

CSS:何時(shí)重要(何時(shí)不)? CSS:何時(shí)重要(何時(shí)不)? Jun 19, 2025 am 12:27 AM

在CSS中,選擇器和屬性名不區(qū)分大小寫,而值、命名顏色、URL和自定義屬性則區(qū)分大小寫。 1.選擇器和屬性名不區(qū)分大小寫,例如background-color和Background-Color相同。 2.值中的十六進(jìn)制顏色不區(qū)分大小寫,但命名顏色區(qū)分大小寫,如red有效而Red無效。 3.URL區(qū)分大小寫,可能導(dǎo)致文件加載問題。 4.自定義屬性(變量)區(qū)分大小寫,使用時(shí)需注意大小寫一致。

什麼是圓錐級函數(shù)? 什麼是圓錐級函數(shù)? Jul 01, 2025 am 01:16 AM

theconic-Gradient()functionIncsscreatesCircularGradientsThatRotateColorStopSaroundAcentralPoint.1.IsidealForPieCharts,ProgressIndicators,colordichers,colorwheels和decorativeBackgrounds.2.itworksbysbysbysbydefindefingincolordefingincolorstopsatspecificains off.

See all articles