Hướng dẫn chi tiết về kiểm tra đơn vị trong các ứng dụng React với Jest và React-Testing

Giới thiệu

Là một nhà phát triển, một trong những điều ở đầu danh sách của bạn phải là gửi mã không có lỗi. Không có gì tệ hơn việc phát hiện ra vào tối thứ Năm rằng những thay đổi bạn thực hiện vào thứ Hai đã phá vỡ ứng dụng trực tiếp. Cách duy nhất để đảm bảo rằng ứng dụng của bạn hoạt động theo yêu cầu của cả hệ thống và người dùng là kiểm tra nó!

Thử nghiệm là một thành phần quan trọng của bất kỳ vòng đời phát triển phần mềm nào và đảm bảo rằng một phần mềm hoạt động đúng và theo kế hoạch. Phát triển web, phát triển ứng dụng dành cho thiết bị di động và quan trọng hơn trong bối cảnh của chúng ta là các ứng dụng React đều tuân theo cùng một nguyên tắc.

Các thành phần phản ứng có thể được kiểm tra theo một số cách khác nhau, được chia thành hai nhóm:

  • Kết xuất các cây thành phần trong một môi trường thử nghiệm đơn giản và đưa ra các xác nhận về hiệu suất của chúng
  • Chạy “kiểm tra đầu cuối”, liên quan đến việc thử nghiệm toàn bộ ứng dụng trong môi trường trình duyệt thực tế

Mặc dù việc thử nghiệm các ứng dụng React có thể được thực hiện theo một số cách, nhưng trong hướng dẫn này, chúng tôi sẽ tạo một ứng dụng React và hướng dẫn đầy đủ về cách chúng tôi có thể thực hiện các bài kiểm tra đơn vị trên ứng dụng React bằng cách sử dụng Thư viện thử nghiệm phản ứng để bạn có thể trau dồi kỹ năng thử nghiệm của mình và tìm hiểu cách tạo một ứng dụng React đơn giản.

Lưu ý: Bạn có thể truy cập vào kho lưu trữ cho hướng dẫn này và khám phá mọi thứ trong đó bằng cách sử dụng liên kết trên GitHub.

Thử nghiệm là gì?

Trước hết, hãy đặt mọi thứ vào một quan điểm. Kiểm tra là một thuật ngữ rất rộng và có thể đề cập đến kiểm thử thủ công, kiểm thử đơn vị, kiểm thử hồi quy, kiểm thử tích hợp, kiểm thử tải, v.v.

Trong ngữ cảnh của kiểm tra đơn vị mà chúng tôi sẽ tập trung vào ngày hôm nay – chúng tôi kiểm tra Chức năng của các đơn vị phân biệt, thường ở cấp độ phương thức. Điều này có thể kiểm tra các giá trị số của đầu ra, độ dài của giá trị đầu ra, hình dạng của chúng, cách phương thức phản ứng với đầu vào không hợp lệ, v.v.

Vì hầu hết các thực hành phần mềm tốt đều ủng hộ các phương thức/chức năng ngắn, có thể thực hiện được, khép kín với mục đích rõ ràng, nên nhiều phương thức sẽ gọi Các phương pháp khác. Thông thường, bạn sẽ muốn thử nghiệm cả phương pháp nội bộ và phương pháp bên ngoài, để đảm bảo rằng bất kỳ thay đổi nào bạn thực hiện trong khi tái cấu trúc, sửa lỗi hoặc cải thiện tính năng đều không phá vỡ bất kỳ chức năng nào khác.

In Phát triển theo hướng kiểm tra (TDD), bạn nên viết một bài kiểm tra và giá trị mong đợi trước khi viết logic cho một phương thức. Đương nhiên, nó sẽ thất bại lúc đầu. Tuy nhiên, sau đó, bạn chỉ cần làm cho nó hoạt động và khi nó vượt qua bài kiểm tra, bạn bắt đầu cấu trúc lại nó để làm cho nó ngắn hơn, sạch hơn, nhanh hơn, v.v. trong khi tái cấu trúc!

Viết bài kiểm tra đơn vị của riêng bạn đặt bạn vào suy nghĩ của ai đó sử dụng phương pháp của bạn, chứ không phải ai đó viết những phương pháp đó, thường giúp có cái nhìn mới mẻ về một tính năng, kết hợp kiểm tra và xác thực bổ sung cũng như tìm kiếm lỗi. Đôi khi, nó dẫn đến thay đổi thiết kế để tạo mã dễ kiểm tra hơn, chẳng hạn như chức năng tách rời để cho phép kiểm tra số cho từng thành phần riêng lẻ.

Sau khi đường cơ sở được thiết lập và mã của bạn vượt qua các bài kiểm tra, bạn có thể thực hiện các thay đổi và xác thực rằng các đơn vị riêng lẻ (thường là các phương thức) hoạt động riêng lẻ. Thử nghiệm đặc biệt hữu ích khi có các bản cập nhật cho cơ sở mã.

Phương pháp thử nghiệm

Thử nghiệm có thể được thực hiện theo hai cách khác nhau: thủ côngtự động. Bằng cách tương tác trực tiếp với một ứng dụng, kiểm tra thủ công sẽ xác minh rằng nó hoạt động bình thường. Kiểm thử tự động là thực hành viết chương trình để thực hiện kiểm tra cho bạn.

Kiểm tra bằng tay

Hầu hết các nhà phát triển xem lại mã của họ theo cách thủ công, vì đây là cách nhanh nhất, tự nhiên nhất và đơn giản nhất để nhanh chóng kiểm tra một chức năng.

Kiểm tra thủ công là bước hợp lý tiếp theo sau khi viết chức năng, giống như việc nếm thử một món ăn sau khi thêm gia vị (thêm một tính năng) để kiểm tra xem nó có hoạt động như mong muốn hay không.

Giả sử rằng, với tư cách là một nhà phát triển được tuyển dụng, bạn đang tạo một biểu mẫu đăng ký. Bạn không chỉ cần đóng trình soạn thảo văn bản của mình và thông báo cho sếp của mình rằng biểu mẫu đã hoàn tất sau khi viết mã. Bạn sẽ mở trình duyệt, thực hiện quy trình biểu mẫu đăng ký và đảm bảo mọi thứ diễn ra theo đúng kế hoạch. Nói cách khác, bạn sẽ kiểm tra mã theo cách thủ công.

Kiểm thử thủ công lý tưởng cho các dự án nhỏ và bạn không cần kiểm thử tự động nếu bạn có ứng dụng danh sách việc cần làm mà bạn có thể kiểm tra thủ công hai phút một lần. Tuy nhiên, tùy thuộc vào kiểm tra thủ công trở nên khó khăn khi ứng dụng của bạn phát triển – có thể trở nên quá dễ dàng để mất tập trung và quên kiểm tra thứ gì đó. Với một danh sách ngày càng tăng của thành phần tương tác, kiểm tra thủ công thậm chí còn khó hơn, đặc biệt nếu bạn đã thử nghiệm một thứ gì đó và chuyển sang một mục mới và bị hỏng tính năng cuối cùng, vì vậy bạn không kiểm tra lại nó trong một thời gian mà không biết rằng nó đã bị hỏng.

Nói một cách đơn giản, thử nghiệm thủ công vẫn ổn khi bắt đầu – nhưng không mở rộng quy mô tốt và không đảm bảo chất lượng mã cho các dự án lớn hơn. Tin tốt là máy tính rất tuyệt vời trong các tác vụ như thế này, chúng tôi đã thử nghiệm tự động để cảm ơn!

Kiểm tra tự động

Trong thử nghiệm tự động, bạn viết mã bổ sung để kiểm tra mã ứng dụng của mình. Sau khi bạn đã viết mã kiểm tra, bạn có thể kiểm tra ứng dụng của bạn bao nhiêu lần tùy thích với nỗ lực tối thiểu.

Có rất nhiều kỹ thuật để viết các bài kiểm tra tự động:

  • Viết chương trình để tự động hóa trình duyệt,
  • Gọi các chức năng trực tiếp từ mã nguồn của bạn,
  • So sánh ảnh chụp màn hình của ứng dụng được kết xuất của bạn…

Mỗi kỹ thuật đều có những ưu điểm riêng, nhưng tất cả chúng đều có một điểm chung – chúng giúp bạn tiết kiệm thời gian và đảm bảo chất lượng mã cao hơn so với thử nghiệm thủ công!

Kiểm thử tự động là tuyệt vời để đảm bảo rằng ứng dụng của bạn đang hoạt động theo đúng kế hoạch. Chúng cũng giúp dễ dàng vượt qua các thay đổi mã trong một ứng dụng.

Các loại kiểm tra

Cho đến nay, chúng tôi đã xem xét các bài kiểm tra ở cấp độ cao. Đã đến lúc thảo luận về các loại bài kiểm tra có thể được viết.

Có ba loại thử nghiệm ứng dụng front-end:

  • Bài kiểm tra đơn vị: Trong các bài kiểm tra đơn vị, các đơn vị hoặc thành phần riêng lẻ của phần mềm được kiểm tra. Một đơn vị riêng lẻ là một chức năng, phương thức, thủ tục, mô-đun, thành phần hoặc đối tượng. Kiểm tra đơn vị cô lập và xác minh một phần mã để xác thực rằng mỗi đơn vị mã của phần mềm hoạt động như mong đợi.
    Các mô-đun hoặc chức năng riêng lẻ được kiểm tra trong kiểm tra đơn vị để đảm bảo rằng chúng hoạt động bình thường như bình thường và tất cả các thành phần cũng được kiểm tra riêng lẻ. Ví dụ, kiểm thử đơn vị sẽ bao gồm việc xác định xem một hàm, một câu lệnh hoặc một vòng lặp trong chương trình có hoạt động bình thường hay không.

  • Kiểm tra ảnh chụp nhanh: Loại thử nghiệm này đảm bảo rằng giao diện người dùng (UI) của ứng dụng web không thay đổi bất ngờ. Nó nắm bắt mã của một thành phần tại một thời điểm cụ thể, cho phép chúng tôi so sánh thành phần đó ở trạng thái này với bất kỳ trạng thái khả dĩ nào khác mà nó có thể thực hiện.
    Kịch bản kiểm tra ảnh chụp nhanh điển hình liên quan đến việc kết xuất một thành phần giao diện người dùng, chụp ảnh chụp nhanh và so sánh ảnh chụp nhanh với tệp ảnh chụp nhanh tham chiếu được lưu giữ cùng với bài kiểm tra. Nếu hai ảnh chụp nhanh khác nhau, thử nghiệm sẽ không thành công vì thay đổi không mong muốn hoặc ảnh chụp nhanh tham chiếu cần được cập nhật để phản ánh thành phần giao diện người dùng mới.

  • Kiểm tra từ đầu đến cuối: Các bài kiểm tra đầu cuối là loại bài kiểm tra dễ hiểu nhất. Thử nghiệm đầu cuối trong các ứng dụng đầu cuối tự động hóa trình duyệt để đảm bảo rằng ứng dụng hoạt động chính xác theo quan điểm của người dùng.
    Các bài kiểm tra đầu cuối tiết kiệm rất nhiều thời gian. Bạn có thể chạy thử nghiệm từ đầu đến cuối bao nhiêu lần tùy thích sau khi viết xong. Cân nhắc xem một bộ gồm hàng trăm bài kiểm tra này có khả năng tiết kiệm bao nhiêu thời gian so với việc viết bài kiểm tra cho từng đơn vị riêng lẻ.
    Với tất cả những lợi ích mà chúng mang lại, các bài kiểm tra đầu cuối có một số vấn đề. Đối với những người mới bắt đầu, các bài kiểm tra từ đầu đến cuối rất tốn thời gian. Một vấn đề khác với các bài kiểm tra đầu cuối là chúng có thể khó gỡ lỗi.

Lưu ý: Để tránh các vấn đề về khả năng lặp lại, các thử nghiệm từ đầu đến cuối có thể được chạy trong môi trường có thể lặp lại, chẳng hạn như bộ chứa docker. Vùng chứa docker và thử nghiệm từ đầu đến cuối nằm ngoài phạm vi của hướng dẫn này, nhưng bạn nên xem xét chúng nếu muốn chạy thử nghiệm từ đầu đến cuối để tránh sự cố lỗi trên các máy khác nhau.

Nếu bạn muốn nắm bắt kiến ​​thức cơ bản về thử nghiệm từ đầu đến cuối với Cypress – hãy đọc của chúng tôi “Thử nghiệm từ đầu đến cuối trong JavaScript với Cypress”!

Ưu điểm và nhược điểm của thử nghiệm

Mặc dù kiểm tra là quan trọng và nên được thực hiện, nhưng như thường lệ, nó có cả lợi ích và hạn chế.

Ưu điểm

  • Nó bảo vệ chống lại hồi quy bất ngờ
  • Kiểm tra đúng cách làm tăng đáng kể chất lượng mã
  • Nó cho phép nhà phát triển tập trung vào nhiệm vụ hiện tại hơn là quá khứ
  • Nó cho phép xây dựng mô-đun của các ứng dụng khó xây dựng
  • Nó loại bỏ nhu cầu xác minh thủ công

Điểm yếus

  • Bạn phải viết thêm mã ngoài việc gỡ lỗi và bảo trì mã, và nhiều người cảm thấy như đó là chi phí không cần thiết trong các dự án nhỏ hơn, bất kể lợi ích là gì
  • Các lỗi thử nghiệm không quan trọng/lành tính có thể dẫn đến việc ứng dụng bị từ chối trong quá trình tích hợp liên tục

Tổng quan về kiểm thử đơn vị

Cho đến nay, chúng tôi đã xem xét thử nghiệm nói chung. Bây giờ là lúc để đi sâu vào tất cả những gì liên quan đến kiểm thử đơn vị và cách viết kiểm thử đơn vị trong các ứng dụng React!

Trước khi định nghĩa kiểm thử đơn vị, chúng ta cần biết rằng một phương pháp thử nghiệm tốt nhằm mục đích tăng tốc thời gian phát triển, giảm lỗi trong ứng dụng và cải thiện chất lượng mã, trong khi phương pháp thử nghiệm kém sẽ làm tê liệt ứng dụng. Kết quả là, với tư cách là nhà phát triển phần mềm, chúng ta phải học các phương pháp kiểm thử đơn vị hiệu quả và một trong số đó là kiểm thử đơn vị.

Một định nghĩa đơn giản về kiểm thử là quá trình kiểm tra xem ứng dụng có hoạt động chính xác hay không. Thử nghiệm đơn vị là quá trình chạy thử nghiệm đối với các thành phần hoặc chức năng của một ứng dụng. Kiểm tra đơn vị là các chức năng gọi các phiên bản biệt lập của các chức năng trong mã nguồn của bạn để xác minh rằng chúng hoạt động như bình thường, một cách xác định.

Ưu điểm của bài kiểm tra đơn vị

Thử nghiệm đơn vị diễn ra nhanh chóng và có thể chạy trong vài giây (riêng lẻ cho một tính năng mới hoặc chạy toàn bộ tất cả các thử nghiệm), cung cấp cho nhà phát triển phản hồi ngay lập tức về việc một tính năng có bị hỏng hay không. Chúng cũng giúp cung cấp tài liệu, bởi vì nếu một nhà phát triển mới tham gia một dự án, họ sẽ cần biết các đơn vị khác nhau của cơ sở mã hoạt động như thế nào; điều này có thể được biết bằng cách xem kết quả của các bài kiểm tra đơn vị.

Nhược điểm của bài kiểm tra đơn vị

Mặc dù các bài kiểm tra đơn vị có những mặt tốt nhưng chúng cũng có những vấn đề riêng. Một vấn đề là mã tái cấu trúc khi nói đến thay đổi thiết kế, vì những điều này có xu hướng khó khăn hơn với các bài kiểm tra đơn vị. Ví dụ: giả sử bạn có một chức năng phức tạp với các bài kiểm tra đơn vị của nó và muốn chia chức năng đó thành nhiều chức năng mô-đun. Một bài kiểm tra đơn vị có thể sẽ thất bại đối với chức năng đó và bạn sẽ cần loại bỏ nó và viết hai bài kiểm tra đơn vị cho các chức năng phân tách. Đây là lý do tại sao thử nghiệm đơn vị hoàn toàn khuyến khích chia nhỏ chúng trước và thử nghiệm chúng riêng lẻ, dẫn đến các thành phần mã mô-đun dễ kiểm tra hơn. Tuy nhiên, trong một số trường hợp, bạn không thể thấy trước những thay đổi có thể xảy ra trong tương lai và lượng thời gian cần thiết để cập nhật các bài kiểm tra đơn vị khiến cho các quy trình tái cấu trúc nghiêm túc trở nên ít hấp dẫn hơn.

Một vấn đề khác với kiểm thử đơn vị là nó chỉ kiểm tra các phần riêng lẻ của ứng dụng, ngay cả khi phần đó là sự kết hợp hợp lý của nhiều phần nhỏ hơn – không có kiểm tra đơn vị cho toàn bộ ứng dụng. Các phần riêng lẻ của ứng dụng có thể hoạt động bình thường, nhưng nếu cách chúng hoạt động khi kết hợp không được thử nghiệm, thì các thử nghiệm có thể trở nên vô dụng. Đó là lý do tại sao các bài kiểm tra đơn vị nên được bổ sung bằng các bài kiểm tra đầu cuối hoặc bài kiểm tra tích hợp hoặc lý tưởng nhất là – cả hai.

Kiểm tra đơn vị một ứng dụng React – Dự án demo

Hãy cùng xem một ví dụ thực tế về kiểm tra đơn vị ứng dụng React!

Trong bản demo này, chúng tôi sẽ thử nghiệm ứng dụng Bộ đếm với nhiều phần khác nhau. Mặc dù nghe có vẻ giống như một ứng dụng khá đơn giản, nhưng nó sẽ là một ví dụ tốt để tìm hiểu cách thức hoạt động của thử nghiệm đơn vị. Bản chất của việc thử nghiệm ứng dụng này là có các khía cạnh khác nhau của thành phần phụ thuộc vào cách người dùng tương tác với nó.

Thiết lập dự án

Sản phẩm create-react-app command, do nhóm React xây dựng, là cách tốt nhất để bắt đầu tạo ứng dụng React quy mô lớn và thế giới thực vì nó sẵn sàng sử dụng và hoạt động dễ dàng với Thư viện thử nghiệm Jest. Nếu bạn mở package.json tệp, bạn sẽ thấy rằng chúng tôi có hỗ trợ mặc định cho Thư viện thử nghiệm phản ứng trong setupTests.js tập tin. Điều này giúp chúng tôi không cần phải cài đặt thủ công Jest vào dự án của mình nếu cần!

Nếu bạn chưa sử dụng nó - hãy chạy nó với npx, sẽ cài đặt nó để sử dụng sau:

$ npx create-react-app react-unit-tests

Nếu bạn đã cài đặt công cụ này, hãy tạo ứng dụng React và đặt tên cho nó react-unit-tests:

$ create-react-app react-unit-tests

Lưu ý: npx sử dụng phiên bản mới nhất của create-react-app, trong khi phiên bản được cài đặt toàn cầu có thể không. Thông thường nên chạy công cụ này qua npx để đảm bảo các phiên bản mới nhất, trừ khi bạn cố tình muốn sử dụng một phiên bản khác.

Tiếp theo, chúng tôi vào thư mục dự án và khởi động máy chủ phát triển:

$ cd react-unit-tests && npm start
// OR
$ cd react-unit-tests && yarn start

Điều này sẽ xuất ứng dụng mới tạo của chúng tôi trong trình duyệt tại localhost:3000.

Lưu ý: Một tính năng tiện dụng ở đây là tải lại nóng được hỗ trợ theo mặc định, vì vậy không cần phải tải lại trình duyệt chỉ để xem các thay đổi mới hoặc cài đặt thủ công nodemon hoặc các thư viện tương tự.

Xây dựng thành phần bộ đếm

Trong tạp chí src thư mục của dự án của chúng tôi, tạo một tệp mới có tên Counter.js. Trong Counter.js, chúng ta sẽ định nghĩa tất cả các phần của thành phần. Nó sẽ chứa các chức năng khác nhau của Bộ đếm, bao gồm increment(), decrement(), restart()switchSign(), đảo ngược giá trị đếm từ âm sang dương khi được nhấp. Các hàm này được tạo để thao tác giá trị đếm ban đầu (được truyền vào dưới dạng chỗ dựa):


import React, { useState } from "react";

function Counter({ initialCount }) {
  const [count, setCount] = useState(initialCount);

  const increment = () => {
    setCount((prev) => prev + 1);
  };

  const decrement = () => {
    setCount((prev) => prev - 1);
  };

  const restart = () => {
    setCount(0);
  };

  const switchSign = () => {
    setCount((prev) => prev * -1);
  };

  return (
    <div>
      <h1>
        Count: <h3>{count}</h3>
      </h1>
      <div>
        <button onClick={increment}>Increment</button>
        <button onClick={decrement}>Decrement</button>
        <button onClick={restart}>Restart</button>
        <button onClick={switchSign}>Switch sign</button>
      </div>
    </div>
  );
}

export default Counter;

Sau đó, cập nhật App.js:


import "./App.css";
import Counter from "./Counter";

function App() {
  return (
    <div className="App">
      <Counter />
    </div>
  );
}

export default App;

Bây giờ, chúng ta có thể xem ứng dụng truy cập trên trình duyệt:

Hướng dẫn dứt khoát về kiểm thử đơn vị trong các ứng dụng React với Jest và React-Testing PlatoBlockchain Data Intelligence. Tìm kiếm dọc. Ái.

Tạo bài kiểm tra cho các thành phần

Hãy tạo một tệp thử nghiệm có tên Counter.test.js để đại diện cho thử nghiệm cho thành phần Counter. Đảm bảo cũng xóa App.test.js để nó không tạo ra kết quả không mong muốn trong khi chúng tôi chạy thử nghiệm.

Lưu ý: Một thực tế phổ biến là đặt tên cho các tệp thử nghiệm của bạn với hậu tố là .test.js, phản ánh tên của tệp/thành phần bạn đang kiểm tra. Điều này đảm bảo tính liên tục giữa các tệp thử nghiệm, các thay đổi chỉ được thực hiện đối với các tệp có liên quan đến mã bạn đang cập nhật khi đẩy các thay đổi (số lượng xung đột hợp nhất thấp hơn) và có thể đọc được.

Ngoài ra, các tệp kiểm tra thường được đặt trong một /test thư mục song song, tương đông vào thư mục gốc của mã nguồn của bạn, tuy nhiên, điều này cũng phụ thuộc vào nhóm.

In Counter.test.js, trước tiên chúng tôi nhập khẩu Counter thành phần, sau đó bắt đầu thử nghiệm với describe() chức năng để mô tả tất cả các chức năng khác nhau có thể xảy ra trong thành phần.

Sản phẩm describe() chức năng được sử dụng để nhóm các bộ kiểm tra cụ thể có thể xảy ra trên một thành phần lại với nhau bằng nhiều it()test() các phương pháp. Đó là một loại trình bao bọc logic, trong đó bạn mô tả chức năng của một loạt bài kiểm tra, với mỗi bài kiểm tra. it() là một thử nghiệm chức năng cho một đơn vị.

Việc kiểm tra các thành phần React của bạn có thể được thực hiện theo cách sao cho chúng tôi có thể sử dụng trình kết xuất thử nghiệm để nhanh chóng tạo giá trị có thể tuần tự hóa cho cây React của bạn thay vì tạo giao diện người dùng đồ họa, điều này sẽ liên quan đến việc tạo ứng dụng hoàn chỉnh.

Kiểm tra giá trị bộ đếm ban đầu

Khi thử nghiệm, nó giúp tạo ra một danh sách có hệ thống các tính năng và khía cạnh của một tính năng nhất định – trạng thái mà các thành phần có thể tồn tại, điều gì có thể ảnh hưởng đến chúng, v.v.

Điều đầu tiên chúng ta sẽ kiểm tra là giá trị đếm ban đầu và cách thành phần xử lý giá đỡ thiết lập nó. với it() phương thức, chúng tôi kiểm tra xem ứng dụng bộ đếm có thực sự hiển thị giá trị đếm ban đầu chính xác đã được chuyển dưới dạng giá trị chống đỡ hay không, đó là 0 trong trường hợp này và truyền hàm gọi lại mô tả tất cả các hành động sẽ xảy ra bên trong thử nghiệm:


import { render, screen } from "@testing-library/react";
import Counter from "./Counter";

describe(Counter, () => {
  it("counter displays correct initial count", () => {
    render(<Counter initialCount={0} />);
    expect(screen.getByTestId("count").textContent).toEqual(0);
  });
});

Ở đây, chúng tôi đã sử dụng screen ví dụ từ thư viện Kiểm tra React để kết xuất thành phần cho mục đích thử nghiệm. Sẽ rất hữu ích khi hiển thị phiên bản giả của một thành phần sẽ được kiểm tra. Và kể từ khi

phần tử giữ count giá trị bị ràng buộc để tự động thay đổi, chúng tôi sử dụng screen.getByTestId() để lắng nghe nó và lấy giá trị của nó với textContent bất động sản.

Xem hướng dẫn thực hành, thực tế của chúng tôi để học Git, với các phương pháp hay nhất, các tiêu chuẩn được ngành công nghiệp chấp nhận và bảng lừa đảo đi kèm. Dừng lệnh Googling Git và thực sự học nó!

Lưu ý: Sản phẩm screen trả về một nút DOM phù hợp cho bất kỳ truy vấn nào hoặc đưa ra lỗi nếu không tìm thấy phần tử nào.

Sau đó, trong Counter.js thành phần, chúng tôi sẽ lắng nghe

yếu tố trong khi kiểm tra bằng cách thiết lập một data-testid thuộc tính cho phần tử có giá trị count:


import React, { useState } from "react";

function Counter({ initialCount }) {
  const [count, setCount] = useState(initialCount);
  const increment = () => {
    setCount((prev) => prev + 1);
  };
  const decrement = () => {
    setCount((prev) => prev - 1);
  };
  const restart = () => {
    setCount(0);
  };
  const switchSign = () => {
    setCount((prev) => prev * -1);
  };

  return (
    <div>
      <h1>
      	
        Count: <h3 data-testid="count">{count}</h3>
      </h1>
      <div>
        <button onClick={increment}>Increment</button>
        <button onClick={decrement}>Decrement</button>
        <button onClick={restart}>Restart</button>
        <button onClick={switchSign}>Switch sign</button>
      </div>
    </div>
  );
}

export default Counter;

Để kiểm tra nếu ban đầu count giá trị bằng 0, chúng tôi sử dụng expect() phương pháp để mô tả những gì được mong đợi của bài kiểm tra mà chúng tôi đã thiết lập! Trong trường hợp của chúng tôi, chúng tôi hy vọng giá trị đếm ban đầu là 0 vì vậy chúng tôi sử dụng toEqual() phương thức, được sử dụng để xác định xem các giá trị của hai đối tượng có khớp nhau hay không. Thay vì xác định danh tính của đối tượng, toEqual() matcher kiểm tra đệ quy tất cả các trường xem có bằng nhau không.

Lưu ý: Bài kiểm tra tập trung cụ thể vào thông tin bạn hiển thị; trong ví dụ của chúng tôi, đó là, Counter thành phần đã nhận được một initialCount chống đỡ. Điều này gợi ý rằng ngay cả khi một tệp khác—giả sử, hãy App.js—có đạo cụ bị thiếu trong Counter thành phần, bài kiểm tra vẫn sẽ vượt qua vì nó chỉ tập trung vào Counter.js và không biết cách sử dụng Counter thành phần. Ngoài ra, do các thử nghiệm độc lập với nhau nên việc hiển thị cùng một thành phần với các đạo cụ khác nhau trong các thử nghiệm khác cũng sẽ không ảnh hưởng.

Bây giờ, chúng ta có thể chạy thử nghiệm thiết lập:

$ yarn test

Bài kiểm tra sẽ thất bại:

FAIL  src/Counter.test.js
  Counter
    × counter displays correct initial count (75 ms)

  ● Counter › counter displays correct initial count

    expect(received).toEqual(expected) // deep equality

    Expected: 0
    Received: "0"

       5 |   it("counter displays correct initial count", () => {
       6 |     render();
    >  7 |     expect(screen.getByTestId("count").textContent).toEqual(0);
         |                                                     ^
       8 |   });
       9 | });
      10 |

      at Object. (src/Counter.test.js:7:53)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        1.929 s, estimated 2 s
Ran all test suites related to changed files.

Thử nghiệm này không thành công vì chúng tôi đã thử nghiệm một số đối với một chuỗi, kết quả là lỗi bình đẳng sâu. Để khắc phục điều đó, đúc các textContent, tức là giá trị ban đầu, trong hàm gọi lại của chúng tôi dưới dạng một số:


import { render, screen } from "@testing-library/react";
import Counter from "./Counter";

describe(Counter, () => {
  it("counter displays correct initial count", () => {
    render(<Counter initialCount={0} />);
     
    expect(Number(screen.getByTestId("count").textContent)).toEqual(0);
  });
});

Bây giờ, mã của chúng tôi sẽ vượt qua bài kiểm tra đầu tiên:

$ yarn test

PASS  src/Counter.test.js
  Counter
    √ counter displays correct initial count (81 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.271 s
Ran all test suites related to changed files.

Đây là một ví dụ đơn giản về cách thử nghiệm trong khi viết logic giúp bạn tránh các vấn đề về sau, trước khi nợ công nghệ ngày càng chồng chất. Việc kiểm tra sớm cũng có thể khiến bạn bị mắc kẹt, vì việc tái cấu trúc và thay đổi logic sẽ tốn kém hơn về mặt thời gian nếu bạn cũng phải viết lại các bài kiểm tra.

Tìm kiếm một sự cân bằng tốt có thể giúp nâng cấp chất lượng phần mềm của bạn, với tác động tiêu cực tối thiểu đến năng suất và tốc độ của bạn.

Kiểm tra nút Tăng

Để kiểm tra rằng increment nút hoạt động như nó phải làm, nghĩa là, để tăng count giá trị bằng một mỗi khi nó được nhấp vào, trước tiên chúng ta cần truy cập vào increment nút, sau đó chúng tôi xác định một nút mới it() phương pháp cho cùng.

Vì giá trị của nút không động, nghĩa là nó sẽ luôn có giá trị Increment bên trong nó, chúng tôi sử dụng getByRole() phương pháp thay vì getByTestId() để truy vấn DOM.

Khi sử dụng getByRole() phương thức, một vai trò mô tả một phần tử HTML.

Chúng ta cũng phải truyền vào một đối tượng để xác định cụ thể là nút nào mà chúng ta muốn kiểm tra, vì có thể có rất nhiều nút khi DOM được hiển thị. Trong đối tượng, chúng tôi thiết lập một name với một giá trị phải giống với văn bản trên nút tăng.

Điều tiếp theo cần làm là mô phỏng sự kiện nhấp chuột bằng cách sử dụng fireEvent() cho phép kích hoạt các sự kiện mô phỏng hành động của người dùng trong khi thử nghiệm.

Đầu tiên, chúng tôi viết một bài kiểm tra để xem liệu giá trị đếm có tăng thêm 1 so với giá trị ban đầu là 0 hay không:


import { fireEvent, render, screen } from "@testing-library/react";
import Counter from "./Counter";

describe(Counter, () => {
  it("counter displays correct initial count", () => {
    render(<Counter initialCount={0} />);
    expect(Number(screen.getByTestId("count").textContent)).toEqual(0);
  });

  it("count should increment by 1 if increment button is clicked", () => {
    render(<Counter initialCount={0} />);
    fireEvent.click(screen.getByRole("button", { name: "Increment" }));
    let countValue = Number(screen.getByTestId("count").textContent);
    expect(countValue).toEqual(1);
  });
});

Kết quả này trong:

$ yarn test

PASS  src/Counter.test.js
  Counter
    √ counter displays correct initial count (79 ms)
    √ count should increment by 1 if increment button is clicked (66 ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        2.405 s
Ran all test suites related to changed files.

Sau đó, chúng ta cũng có thể viết một bài kiểm tra để kiểm tra xem count giá trị là 0 trước khi nút được nhấp bằng cách xác định hai expect() các phương thức - một phương thức trước khi sự kiện nhấp chuột được kích hoạt và một phương thức khác sau sự kiện nhấp chuột được kích hoạt:


it("count should increment by 1 if increment button is clicked", () => {
    render(<Counter initialCount={0} />);
    let countValue1 = Number(screen.getByTestId("count").textContent);
    expect(countValue1).toEqual(0);
    fireEvent.click(screen.getByRole("button", { name: "Increment" }));
    let countValue2 = Number(screen.getByTestId("count").textContent);
    expect(countValue2).toEqual(1);
});

Các bài kiểm tra vẫn vượt qua:

$ yarn test

PASS  src/Counter.test.js
  Counter
    √ counter displays correct initial count (82 ms)
    √ count should increment by 1 if increment button is clicked (60 ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        2.388 s
Ran all test suites related to changed files.

Kiểm tra nút Giảm

Theo cách tương tự, chúng tôi đã viết bài kiểm tra cho Increment nút, chúng tôi xác định thử nghiệm cho Decrement nút như vậy:


it("count should decrement by 1 if decrement button is clicked", () => {
  render(<Counter initialCount={0} />);
  fireEvent.click(screen.getByRole("button", { name: "Decrement" }));
  let countValue = Number(screen.getByTestId("count").textContent);
  expect(countValue).toEqual(-1);
});

Kết quả này trong:

$ yarn test

PASS  src/Counter.test.js
  Counter
    √ counter displays correct initial count (79 ms)
    √ count should increment by 1 if increment button is clicked (73 ms)
    √ count should decrement by 1 if decrement button is clicked (21 ms)

Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        2.346 s
Ran all test suites related to changed files.

Kiểm tra nút Khởi động lại

Tương tự như IncrementDecrement các nút, chúng tôi xác định thử nghiệm cho Restart nút như vậy:


it("count should reset to 0 if restart button is clicked", () => {
  render(<Counter initialCount={50} />);
  fireEvent.click(screen.getByRole("button", { name: "Restart" }));
  let countValue = Number(screen.getByTestId("count").textContent);
  expect(countValue).toEqual(0);
});

Với mục đích thử nghiệm, giá trị ban đầu được đặt thành 50 (giá trị tùy ý) và khi chạy thử nghiệm, cả bốn thử nghiệm đều vượt qua thành công:

$ yarn test

PASS  src/Counter.test.js
  Counter
    √ counter displays correct initial count (81 ms)
    √ count should increment by 1 if increment button is clicked (57 ms)
    √ count should decrement by 1 if decrement button is clicked (21 ms)
    √ count should reset to 0 if restart button is clicked (16 ms)

Test Suites: 1 passed, 1 total
Tests:       4 passed, 4 total
Snapshots:   0 total
Time:        2.583 s
Ran all test suites related to changed files.

Kiểm tra nút Switch Sign

Chúng tôi cũng viết bài kiểm tra để đảo ngược dấu hiệu trên count giá trị bằng cách thiết lập giá trị của count đến 50 trong tệp thử nghiệm. Sau đó, hãy tìm dấu hiệu nào được hiển thị trước và sau khi nút kích hoạt sự kiện nhấp chuột:


it("count invert signs if switch signs button is clicked", () => {
  render(<Counter initialCount={50} />);
  let countValue1 = Number(screen.getByTestId("count").textContent);
  expect(countValue1).toEqual(50);
  fireEvent.click(screen.getByRole("button", { name: "Switch signs" }));
  let countValue2 = Number(screen.getByTestId("count").textContent);
  expect(countValue2).toEqual(-50);
});

Kết quả này trong:

$ yarn test

PASS  src/Counter.test.js
  Counter
    √ counter displays correct initial count (91 ms)
    √ count should increment by 1 if increment button is clicked (72 ms)
    √ count should decrement by 1 if increment button is clicked (21 ms)
    √ count should reset to 0 if restart button is clicked (19 ms)
    √ count invert signs if switch signs button is clicked (14 ms)

Test Suites: 1 passed, 1 total
Tests:       5 passed, 5 total
Snapshots:   0 total
Time:        3.104 s
Ran all test suites related to changed files.

Ồ! Tất cả các bài kiểm tra đã vượt qua thành công cho ứng dụng truy cập của chúng tôi.

Viết bài kiểm tra không khó – chúng tôi mô phỏng hiệu quả các trường hợp sử dụng của một tính năng để đảm bảo tính năng đó không bị hỏng khi được sử dụng như dự định và ngoài ý muốn. Có ai đó cung cấp một giá trị ngoài giới hạn? Một định dạng sai? Ứng dụng sẽ giải quyết vấn đề thay vì thất bại.

Nói chung, một điểm khởi đầu tốt để thử nghiệm là:

  • Kiểm tra hành vi dự định (bất kể tính năng của bạn là gì)
  • Kiểm tra tất cả các khía cạnh của hành vi ngoài ý muốn (đầu vào sai, chẳng hạn như định dạng không được hỗ trợ, giới hạn, v.v.)
  • Kiểm tra bằng số (nếu tính năng của bạn tạo ra các giá trị số có thể xác minh được, hãy tính toán kết quả bằng tay và kiểm tra xem nó có trả về kết quả đúng không)

Các phương pháp hay nhất để kiểm tra đơn vị

  • Các xét nghiệm phải mang tính quyết định: Chạy các thử nghiệm giống nhau trên cùng một thành phần nhiều lần sẽ mang lại kết quả giống nhau mỗi lần. Bạn phải đảm bảo rằng ảnh chụp nhanh được tạo của bạn không chứa dữ liệu dành riêng cho nền tảng hoặc dữ liệu không xác định khác.

  • Tránh các xét nghiệm không cần thiết: Các bài kiểm tra tốt không đi kèm với những kỳ vọng hoặc trường hợp kiểm tra không cần thiết.
    Chúng ta có thể hiểu rõ hơn bằng cách xem xét các bài kiểm tra dưới đây:

test('the success modal is visible', () => {});
test('the success modal has a success message', () => {});

Nếu chúng ta biết rằng thông báo thành công bên trong phương thức thành công hiển thị, thì điều đó có nghĩa là bản thân phương thức thành công cũng hiển thị. Vì vậy, trong trường hợp này, chúng tôi có thể xóa thử nghiệm đầu tiên một cách an toàn và chỉ thực hiện thử nghiệm thứ hai hoặc kết hợp chúng lại với nhau. Có nhiều bài kiểm tra có thể mang lại cảm giác an toàn sai lầm nếu chúng thừa.

  • Tránh để lộ logic bên trong: Nếu thử nghiệm của bạn thực hiện một hành động mà người dùng của bạn không thực hiện (chẳng hạn như thử nghiệm một phương pháp nội bộ không được hiển thị cho người dùng), thì rất có thể bạn đang thử nghiệm chi tiết triển khai. Cuối cùng, bạn có thể để lộ một chức năng riêng tư chỉ để kiểm tra thành phần của mình. Đây là một mùi mã nên tránh. Thay vào đó, hãy cấu trúc lại cơ sở mã của bạn để chức năng riêng tư có thể kiểm tra được mà không bị lộ công khai.

  • Tránh thử nghiệm chi tiết triển khai: Nếu ứng dụng của chúng tôi tăng xy - liệu x được tăng lên trước hay không có khả năng không có ý nghĩa gì, miễn là kết quả là như nhau. Bạn sẽ luôn có thể cấu trúc lại, thay đổi và cập nhật chi tiết triển khai mà không phá vỡ các bài kiểm tra, nếu không, các thử nghiệm sẽ xúc tác cho việc tích lũy nợ công nghệ bằng cách tăng chi phí tái cấu trúc và tối ưu hóa.

  • Đặt logic nghiệp vụ vào các chức năng thuần túy thay vì các thành phần giao diện người dùng.

Kết luận

Hướng dẫn này chủ yếu là về thử nghiệm đơn vị. Tuy nhiên, điều quan trọng là trước tiên chúng tôi hiểu và đánh giá cao tất cả những gì liên quan đến thử nghiệm, bao gồm ý nghĩa của nó, cách tiếp cận thử nghiệm, các loại thử nghiệm cũng như ưu điểm và nhược điểm của nó.

Điều quan trọng là phải nhớ lý do tại sao bạn viết bài kiểm tra trong khi bạn đang viết chúng. Thông thường, mục tiêu của các bài kiểm tra viết là để tiết kiệm thời gian. Các thử nghiệm sẽ mang lại lợi nhuận nếu dự án bạn đang thực hiện ổn định và sẽ được phát triển trong một thời gian dài. Với điều này, có thể nói rằng việc thử nghiệm một ứng dụng có thể được coi là không đáng nếu nó không giúp bạn tiết kiệm thời gian phát triển. Trên hết, các bài kiểm tra tốt rất đơn giản để duy trì và mang lại sự tự tin khi thay đổi mã của bạn.

Chúng tôi cũng đã học cách truy vấn DOM trong khi thử nghiệm các ứng dụng React bằng cách sử dụng getByTestId() phương pháp. Nó rất hữu ích để xác định vùng chứa và truy vấn các phần tử bằng văn bản động, nhưng nó không phải là truy vấn mặc định của bạn. Thay vì sử dụng getByTestId() phương pháp ngay lập tức, trước tiên hãy thử một trong những cách sau:

  • getByRole() – nó truy vấn một phần tử đồng thời đảm bảo rằng nó có thể truy cập được với vai trò và văn bản chính xác
  • getByLabelText() – đó là một truy vấn tuyệt vời để tương tác với các phần tử biểu mẫu, nó cũng kiểm tra xem các nhãn của chúng tôi có được liên kết đúng với đầu vào của chúng tôi thông qua các thuộc tính for và id hay không
  • getByText() – Khi cả hai truy vấn trước đó đều không khả dụng, getByText() phương pháp sẽ hữu ích trong việc truy cập các phần tử dựa trên văn bản hiển thị cho người dùng
  • getByPlaceholderText(): Truy vấn này rất phù hợp hơn với id thử nghiệm khi tất cả những gì bạn phải truy vấn một phần tử là trình giữ chỗ.

Chúng tôi hy vọng rằng hướng dẫn này hữu ích cho bạn! Bạn có thể truy cập vào kho lưu trữ cho hướng dẫn này và khám phá mọi thứ trong đó bằng cách sử dụng liên kết trên GitHub.

Dấu thời gian:

Thêm từ xếp chồng lên nhau