Hướng dẫn how unit testing is done in python? - cách kiểm tra đơn vị được thực hiện trong python?

Cập nhật lần cuối vào ngày 21 tháng 6 năm 2022

Kiểm tra đơn vị là một phương pháp để kiểm tra phần mềm xem xét các đoạn mã có thể kiểm tra nhỏ nhất, được gọi là đơn vị, được kiểm tra để hoạt động chính xác. Bằng cách thực hiện kiểm tra đơn vị, chúng tôi có thể xác minh rằng mỗi phần của mã, bao gồm các chức năng trợ giúp có thể không được tiếp xúc với người dùng, hoạt động chính xác và như dự định.

Ý tưởng là chúng tôi đang độc lập kiểm tra từng phần nhỏ của chương trình để đảm bảo rằng nó hoạt động. Điều này tương phản với thử nghiệm hồi quy và tích hợp, kiểm tra rằng các phần khác nhau của chương trình hoạt động tốt với nhau và như dự định.

Trong bài đăng này, bạn sẽ khám phá cách thực hiện thử nghiệm đơn vị trong Python bằng hai khung thử nghiệm đơn vị phổ biến: khung pyunit tích hợp và khung pytest.

Sau khi hoàn thành hướng dẫn này, bạn sẽ biết:

  • Thư viện kiểm tra đơn vị trong Python như Pyunit và Pytest
  • Kiểm tra hành vi chức năng dự kiến ​​thông qua việc sử dụng các bài kiểm tra đơn vị

Khởi động dự án của bạn với cuốn sách mới Python for Machine Learning, bao gồm các hướng dẫn từng bước và các tệp mã nguồn Python cho tất cả các ví dụ. with my new book Python for Machine Learning, including step-by-step tutorials and the Python source code files for all examples.

Bắt đầu nào!

Hướng dẫn how unit testing is done in python? - cách kiểm tra đơn vị được thực hiện trong python?

Giới thiệu nhẹ nhàng về thử nghiệm đơn vị ở Pythonphoto của Bee Naturalles. Một số quyền được bảo lưu.
Photo by Bee Naturalles. Some rights reserved.

Tổng quan

Hướng dẫn được chia thành năm phần; họ đang:

  • Các bài kiểm tra đơn vị là gì, và tại sao chúng lại quan trọng?
  • Phát triển theo hướng thử nghiệm (TDD) là gì?
  • Sử dụng khung pyunit tích hợp Python
  • Sử dụng thư viện pytest
  • Kiểm tra đơn vị trong hành động

Các bài kiểm tra đơn vị là gì, và tại sao chúng lại quan trọng?

Hãy nhớ làm toán trở lại ở trường, hoàn thành các thủ tục số học khác nhau trước khi kết hợp chúng để có được câu trả lời chính xác? Hãy tưởng tượng làm thế nào bạn sẽ kiểm tra để đảm bảo rằng các tính toán được thực hiện ở mỗi bước là chính xác và bạn đã không phạm phải bất kỳ sai lầm bất cẩn nào hoặc viết sai bất cứ điều gì.

Bây giờ, mở rộng ý tưởng đó để mã! Chúng tôi muốn liên tục xem qua mã của mình để xác minh định nghĩa tính đúng đắn của nó, vậy làm thế nào bạn sẽ tạo một thử nghiệm để đảm bảo rằng đoạn mã sau thực sự trả về khu vực của hình chữ nhật?

def calculate_area_rectangle (chiều rộng, chiều cao):calculate_area_rectangle(width,height):

& nbsp; & nbsp; & nbsp; & nbsp; returnWidth *chiều caoreturnwidth *height

Chúng tôi có thể chạy mã với một vài ví dụ thử nghiệm và xem liệu nó có trả về đầu ra dự kiến ​​không.

Đó là ý tưởng của một bài kiểm tra đơn vị! Một thử nghiệm đơn vị là một thử nghiệm kiểm tra một thành phần của mã, thường được mô đun hóa thành một hàm và đảm bảo rằng nó thực hiện như mong đợi.

Các thử nghiệm đơn vị là một phần quan trọng của kiểm tra hồi quy để đảm bảo rằng mã vẫn hoạt động như mong đợi sau khi thực hiện các thay đổi đối với mã và giúp đảm bảo tính ổn định của mã. Sau khi thực hiện các thay đổi đối với mã của chúng tôi, chúng tôi có thể chạy các thử nghiệm đơn vị mà chúng tôi đã tạo trước đây để đảm bảo rằng chức năng hiện có trong các phần khác của cơ sở mã không bị ảnh hưởng bởi các thay đổi của chúng tôi.

Một lợi ích quan trọng khác của các bài kiểm tra đơn vị là chúng giúp dễ dàng cô lập các lỗi. Hãy tưởng tượng chạy toàn bộ dự án và nhận được một chuỗi các lỗi. Làm thế nào chúng ta có thể gỡ lỗi mã của chúng tôi?

Đó là nơi mà các bài kiểm tra đơn vị xuất hiện. Chúng tôi có thể phân tích các đầu ra của các thử nghiệm đơn vị của chúng tôi để xem liệu có thành phần nào của mã của chúng tôi đã bị lỗi và bắt đầu gỡ lỗi từ đó không. Điều đó không thể nói rằng thử nghiệm đơn vị luôn có thể giúp chúng tôi tìm thấy lỗi, nhưng nó cho phép điểm khởi đầu thuận tiện hơn nhiều trước khi chúng tôi bắt đầu xem xét việc tích hợp các thành phần trong thử nghiệm tích hợp.

Đối với phần còn lại của bài viết, chúng tôi sẽ chỉ ra cách kiểm tra đơn vị bằng cách kiểm tra các chức năng trong lớp hình chữ nhật này:

classRectangle:Rectangle:

& nbsp; & nbsp; & nbsp; & nbsp; def __init __ (tự, chiều rộng, chiều cao):def __init__(self,width,height):

        self.width=widthself.width=width

        self.height=heightself.height =height

& nbsp; & nbsp; & nbsp; & nbsp; def get_area (self):def get_area(self):

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;returnself.width *self.height

& nbsp; & nbsp; & nbsp; & nbsp; def set_width (self, width):def set_width(self,width):

        self.width=widthself.width=width

& nbsp; & nbsp; & nbsp; & nbsp; def set_height (tự, chiều cao):def set_height(self,height):

        self.height=heightself.height=height

Bây giờ chúng tôi đã thúc đẩy các bài kiểm tra đơn vị, hãy để khám phá cách chính xác chúng tôi có thể sử dụng các thử nghiệm đơn vị như một phần của đường ống phát triển của chúng tôi và cách thực hiện chúng trong Python!

Hướng phát triển thử nghiệm

Thử nghiệm rất quan trọng đối với sự phát triển phần mềm tốt mà thậm chí còn có một quy trình phát triển phần mềm dựa trên thử nghiệm, phát triển theo hướng thử nghiệm (TDD). Ba quy tắc của TDD được đề xuất bởi Robert C. Martin là:

  • Bạn không được phép viết bất kỳ mã sản xuất nào trừ khi đó là để thực hiện vượt qua bài kiểm tra đơn vị thất bại.
  • Bạn không được phép viết thêm một bài kiểm tra đơn vị hơn là đủ để thất bại và các lỗi biên dịch là thất bại.
  • Bạn không được phép viết bất kỳ mã sản xuất nào hơn là đủ để vượt qua một bài kiểm tra đơn vị thất bại.

Ý tưởng chính của TDD là chúng tôi dựa trên sự phát triển phần mềm của chúng tôi xung quanh một tập hợp các bài kiểm tra đơn vị mà chúng tôi đã tạo, điều này làm cho đơn vị kiểm tra trung tâm của quy trình phát triển phần mềm TDD. Bằng cách này, bạn yên tâm rằng bạn có một bài kiểm tra cho mọi thành phần bạn phát triển.

TDD cũng thiên về việc có các thử nghiệm nhỏ hơn, có nghĩa là các thử nghiệm cụ thể hơn và thử nghiệm ít thành phần hơn tại một thời điểm. Điều này hỗ trợ trong việc theo dõi các lỗi và các bài kiểm tra nhỏ hơn cũng dễ đọc và hiểu hơn vì có ít thành phần hơn khi chơi trong một lần chạy.

Nó không có nghĩa là bạn phải sử dụng TDD cho các dự án của mình. Nhưng bạn có thể coi đó là một phương pháp để phát triển mã của bạn và các bài kiểm tra cùng một lúc.

Bạn muốn bắt đầu với Python để học máy?

Tham gia khóa học gặp sự cố email 7 ngày miễn phí của tôi ngay bây giờ (với mã mẫu).

Nhấp để đăng ký và cũng nhận được phiên bản Ebook PDF miễn phí của khóa học.

Sử dụng khung pyunit tích hợp Python

Bạn có thể tự hỏi, tại sao chúng ta cần các khung kiểm tra đơn vị kể từ khi Python và các ngôn ngữ khác cung cấp từ khóa assert? Khung kiểm tra đơn vị giúp tự động hóa quá trình thử nghiệm và cho phép chúng tôi chạy nhiều thử nghiệm trên cùng một chức năng với các tham số khác nhau, kiểm tra các ngoại lệ dự kiến ​​và nhiều trường hợp khác.

Pyunit là khung thử nghiệm đơn vị tích hợp Python, và phiên bản Python, của khung thử nghiệm JUnit tương ứng cho Java. Để bắt đầu xây dựng một tệp thử nghiệm, chúng tôi cần nhập thư viện unittest để sử dụng Pyunit:

Sau đó, chúng tôi có thể bắt đầu viết ra bài kiểm tra đơn vị đầu tiên. Các thử nghiệm đơn vị trong Pyunit được cấu trúc dưới dạng các lớp con của lớp unittest.TestCase và chúng tôi có thể ghi đè phương thức runTest() để thực hiện các thử nghiệm đơn vị của chúng tôi kiểm tra các điều kiện bằng các hàm khẳng định khác nhau trong unittest.TestCase:

classTestGetAreaRectangle(unittest.TestCase):TestGetAreaRectangle(unittest.TestCase):

& nbsp; & nbsp; & nbsp; & nbsp; def runtest (self):def runTest(self):

        rectangle=Rectangle(2,3)rectangle= Rectangle(2,3)

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;self.assertEqual(rectangle.get_area(),6,"incorrect area")

Đó là bài kiểm tra đơn vị đầu tiên của chúng tôi! Nó kiểm tra xem phương thức rectangle.get_area() có trả về khu vực chính xác cho hình chữ nhật có chiều rộng = 2 và chiều dài = 3. Chúng tôi sử dụng self.assertEqual thay vì chỉ sử dụng assert để cho phép thư viện unittest cho phép người chạy tích lũy tất cả các trường hợp thử nghiệm và tạo báo cáo.

Sử dụng các chức năng khẳng định khác nhau trong unittest.TestCase cũng cho chúng ta khả năng tốt hơn để kiểm tra các hành vi khác nhau như unittest0. Điều này cho phép chúng tôi kiểm tra xem một khối mã nhất định tạo ra một ngoại lệ dự kiến.

Để chạy bài kiểm tra đơn vị, chúng tôi thực hiện cuộc gọi đến unittest1 trong chương trình của chúng tôi,

Vì mã trả về đầu ra dự kiến ​​cho trường hợp này, nó trả về rằng các thử nghiệm chạy thành công, với đầu ra:

.

---------------------------------------------------------- --------------------

Chạy 1 bài kiểm tra trong 0,003 giây

ĐƯỢC RỒI

Mã hoàn chỉnh như sau:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

Nhập khẩu Unittestunittest

# Mã của chúng tôi sẽ được kiểm tra

classRectangle:Rectangle:

& nbsp; & nbsp; & nbsp; & nbsp; def __init __ (tự, chiều rộng, chiều cao):def __init__(self,width,height):

        self.width=widthself.width =width

        self.height=heightself.height=height

& nbsp; & nbsp; & nbsp; & nbsp; def get_area (self):def get_area(self):

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;return self.width *self.height

& nbsp; & nbsp; & nbsp; & nbsp; def set_width (self, width):def set_width(self,width):

        self.width=widthself.width=width

& nbsp; & nbsp; & nbsp; & nbsp; def set_height (tự, chiều cao):def set_height(self,height):

        self.height=heightself.height=height

# Bài kiểm tra dựa trên mô -đun Unittest

classTestGetAreaRectangle(unittest.TestCase): TestGetAreaRectangle(unittest.TestCase):

& nbsp; & nbsp; & nbsp; & nbsp; def runtest (self):def runTest(self):

        rectangle=Rectangle(2,3)rectangle=Rectangle(2, 3)

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;self.assertEqual(rectangle.get_area(),6,"incorrect area")

Đó là bài kiểm tra đơn vị đầu tiên của chúng tôi! Nó kiểm tra xem phương thức rectangle.get_area() có trả về khu vực chính xác cho hình chữ nhật có chiều rộng = 2 và chiều dài = 3. Chúng tôi sử dụng self.assertEqual thay vì chỉ sử dụng assert để cho phép thư viện unittest cho phép người chạy tích lũy tất cả các trường hợp thử nghiệm và tạo báo cáo.

unittest.main().main()

Sử dụng các chức năng khẳng định khác nhau trong unittest.TestCase cũng cho chúng ta khả năng tốt hơn để kiểm tra các hành vi khác nhau như unittest0. Điều này cho phép chúng tôi kiểm tra xem một khối mã nhất định tạo ra một ngoại lệ dự kiến. While in the above, our business logic unittest2 class and our test code unittest3 are put together. In reality, you may put them in separate files and unittest4 the business logic into your test code. This can help you better manage the code.

Để chạy bài kiểm tra đơn vị, chúng tôi thực hiện cuộc gọi đến unittest1 trong chương trình của chúng tôi,

classTestGetAreaRectangle(unittest.TestCase):TestGetAreaRectangle(unittest.TestCase):

Vì mã trả về đầu ra dự kiến ​​cho trường hợp này, nó trả về rằng các thử nghiệm chạy thành công, với đầu ra:def test_normal_case(self):

        rectangle=Rectangle(2,3)rectangle= Rectangle(2,3)

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;self.assertEqual(rectangle.get_area(),6,"incorrect area")

& nbsp; & nbsp; & nbsp; & nbsp;def test_negative_case(self):

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;"""expect -1 as output to denote error when looking at negative area"""

        rectangle=Rectangle(-1,2)rectangle= Rectangle(-1,2)

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;self.assertEqual(rectangle.get_area(),-1,"incorrect negative output")

Chạy điều này sẽ cho chúng tôi lỗi đầu tiên của chúng tôi:

F.

================================================== ====================

FAIL: test_negative_case (__main __. TestGetArectANGLE)

mong đợi -1 là đầu ra để biểu thị lỗi khi nhìn vào vùng tiêu cực

---------------------------------------------------------- --------------------

Traceback (cuộc gọi gần đây nhất cuối cùng):

Tệp "", dòng 9, trong test_negative_case

self.assertequal (hình chữ nhật.get_area (), -1, "đầu ra âm không chính xác")

AssitSerRor: -2! = -1: Đầu ra âm không chính xác

---------------------------------------------------------- --------------------

Traceback (cuộc gọi gần đây nhất cuối cùng):

Tệp "", dòng 9, trong test_negative_case

self.assertequal (hình chữ nhật.get_area (), -1, "đầu ra âm không chính xác")

AssitSerRor: -2! = -1: Đầu ra âm không chính xác

Đã chạy 2 bài kiểm tra trong 0,003 giâytest_geq(self):

Thất bại (thất bại = 1)"""tests if value is greater than or equal to a particular target"""

  self.assertGreaterEqual(self.rectangle.get_area(),-1)self.assertGreaterEqual(self.rectangle.get_area(), -1)

Chúng ta có thể thấy bài kiểm tra đơn vị không thành công, đó là unittest7 được nhấn mạnh trong đầu ra cùng với thông báo Stderr vì unittest8 không trả về -1 như chúng ta mong đợi trong thử nghiệm của chúng ta.

Có nhiều loại chức năng khẳng định khác nhau được xác định trong Unittest. Ví dụ: chúng ta có thể sử dụng lớp TestCase:test_assert_raises(self):

DEF TEST_GEQ (tự):"""using assertRaises to detect if an expected error is raised when running a particular block of code"""

& nbsp; & nbsp; "" "Các kiểm tra nếu giá trị lớn hơn hoặc bằng một mục tiêu cụ thể" ""with self.assertRaises(ZeroDivisionError):

    a=1/0a =1/0

Chúng tôi thậm chí có thể kiểm tra xem một ngoại lệ cụ thể có bị ném trong quá trình thực thi hay không:

classTestGetAreaRectangleWithSetUp(unittest.TestCase):TestGetAreaRectangleWithSetUp(unittest.TestCase):

DEC TEST_ASSERT_RAISE (tự):def setUp(self):

    self.rectangle=Rectangle(0,0)self.rectangle= Rectangle(0,0)

& nbsp; & nbsp; "" "Sử dụng Assertraises để phát hiện nếu lỗi dự kiến ​​được nêu ra khi chạy một khối mã cụ thể" ""def test_normal_case(self):

    self.rectangle.set_width(2)self.rectangle.set_width(2)

    self.rectangle.set_height(3)self.rectangle.set_height(3)

& nbsp; & nbsp; với self.assertraise (zerodivisionerror):self.assertEqual(self.rectangle.get_area(),6,"incorrect area")

Bây giờ, chúng tôi xem xét xây dựng các bài kiểm tra của chúng tôi. Điều gì sẽ xảy ra nếu chúng ta có một số mã mà chúng ta cần chạy để thiết lập trước khi chạy từng bài kiểm tra? Vâng, chúng ta có thể ghi đè phương thức thiết lập trong Unittest.testcase.def test_negative_case(self):

& nbsp; & nbsp; setup def (self):"""expect -1 as output to denote error when looking at negative area"""

    self.rectangle.set_width(-1)self.rectangle.set_width(-1)

    self.rectangle.set_height(2)self.rectangle.set_height(2)

& nbsp; & nbsp; def test_normal_case (self):self.assertEqual(self.rectangle.get_area(), -1,"incorrect negative output")

& nbsp;

& nbsp; & nbsp; def test_negative_case (self):

& nbsp; & nbsp; & nbsp; & nbsp; "" "kỳ vọng -1 là đầu ra để biểu thị lỗi khi nhìn vào khu vực tiêu cực" ""

classTestGetAreaRectangleWithSetUp(unittest.TestCase):TestGetAreaRectangleWithSetUp(unittest.TestCase):

  @classmethod@classmethod

& nbsp; & nbsp; & nbsp; & nbsp; self.assertequal (self.rectangle.get_area (),-1, "đầu ra âm không chính xác")setUpClass(self):

    self.rectangle=Rectangle(0,0)self.rectangle= Rectangle(0,0)

Trong ví dụ mã trên, chúng tôi đã ghi đè phương thức unittest9 từ unittest.TestCase, với phương thức unittest9 của chính chúng tôi để khởi tạo đối tượng unittest2. Phương pháp unittest9 này được chạy trước mỗi bài kiểm tra đơn vị và hữu ích trong việc tránh sao chép mã khi nhiều thử nghiệm dựa trên cùng một đoạn mã để thiết lập thử nghiệm. Điều này tương tự như nhà trang trí unittest.TestCase4 trong JUnit.

Tương tự như vậy, có một phương thức unittest.TestCase5 mà chúng ta cũng có thể ghi đè cho mã được thực thi sau mỗi lần kiểm tra.

Để chỉ chạy phương thức một lần cho mỗi lớp TestCase, chúng ta cũng có thể sử dụng phương thức careSclass như sau:..

setupclass def (self):

Mã trên chỉ được chạy một lần cho mỗi TestCase thay vì một lần mỗi lần chạy thử như trường hợp thiết lập.=unittest.TestLoader()\

Để giúp chúng tôi tổ chức các bài kiểm tra và chọn bộ thử nghiệm nào chúng tôi muốn chạy, chúng tôi có thể tổng hợp các trường hợp thử nghiệm vào các bộ thử nghiệm giúp nhóm kiểm tra nên được thực hiện với nhau thành một đối tượng duy nhất:.loadTestsFromTestCase(TestGetAreaRectangleWithSetUp)

...

runner=unittest.TextTestRunner()=unittest.TextTestRunner()

runner.run(calculate_area_suite).run(calculate_area_suite)

# Tải tất cả các bài kiểm tra đơn vị từ TestGetAreeChangle vào bộ thử nghiệm

calculate_area_suite = unittest.testloader () \

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

classTestGetAreaRectangleWithSetUp(unittest.TestCase):TestGetAreaRectangleWithSetUp(unittest.TestCase):

  @classmethod@classmethod

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; .LoadTestSFromTestCase (TestGetAreceChiWithSetUp)def setUpClass(self):

Ở đây, chúng tôi cũng giới thiệu một cách khác để chạy các bài kiểm tra trong Pyunit bằng cách sử dụng lớp unittest.TestCase6, cho phép chúng tôi chạy các bộ thử nghiệm cụ thể.#this method is only run once for the entire class rather than being run for each test which is done for setUp()

    self.rectangle=Rectangle(0,0)self.rectangle=Rectangle(0,0)

& nbsp; & nbsp; def test_normal_case (self):def test_normal_case(self):

    self.rectangle.set_width(2)self.rectangle.set_width(2)

    self.rectangle.set_height(3)self.rectangle.set_height(3)

& nbsp;self.assertEqual(self.rectangle.get_area(),6,"incorrect area")

& nbsp; & nbsp; DEF test_geq (self):def test_geq(self):

& nbsp; & nbsp; & nbsp; & nbsp; "" "" Kiểm tra nếu giá trị lớn hơn hoặc bằng một mục tiêu cụ thể "" """"tests if value is greater than or equal to a particular target"""

    self.assertGreaterEqual(self.rectangle.get_area(),-1)self.assertGreaterEqual(self.rectangle.get_area(), -1)

& nbsp; & nbsp; def test_assert_raises (self):def test_assert_raises(self):

& nbsp; & nbsp; & nbsp; & nbsp; "" "Sử dụng Assertraises để phát hiện nếu một lỗi dự kiến ​​được nêu ra khi chạy một khối mã cụ thể" """""using assertRaises to detect if an expected error is raised when running a particular block of code"""

& nbsp;with self.assertRaises(ZeroDivisionError):

      a=1/0a=1/0

Đây chỉ là phần nổi của tảng băng với những gì bạn có thể làm với Pyunit. Chúng ta cũng có thể viết các bài kiểm tra tìm kiếm các thông báo ngoại lệ khớp với biểu thức regex hoặc ________ 28/________ 29 Các phương thức chỉ được chạy một lần - ví dụ (____ 30).

Sử dụng pytest

Pytest là một thay thế cho mô-đun Unittest tích hợp. Để bắt đầu với pytest, trước tiên bạn sẽ cần cài đặt nó, điều mà bạn có thể làm bằng cách sử dụng:

Để viết các bài kiểm tra, bạn chỉ cần viết các chức năng với tên được đặt trước với quy trình khám phá thử nghiệm ____ ____16, và và pytest sẽ có thể tìm thấy các bài kiểm tra của bạn, ví dụ:

def test_normal_case (self):test_normal_case(self):

    rectangle=Rectangle(2,3)rectangle=Rectangle(2,3)

& nbsp; & nbsp; & nbsp; & nbsp; assertrectangle.get_area () == 6, "khu vực không chính xác"assertrectangle.get_area() ==6,"incorrect area"

Bạn sẽ nhận thấy rằng Pytest sử dụng từ khóa assert tích hợp của Python, thay vì tập hợp các chức năng khẳng định của riêng nó như Pyunit, có thể giúp nó thuận tiện hơn một chút vì chúng tôi có thể tránh tìm kiếm các chức năng khẳng định khác nhau.

Mã hoàn chỉnh như sau:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

# Mã của chúng tôi sẽ được kiểm tra

classRectangle:Rectangle:

& nbsp; & nbsp; & nbsp; & nbsp; def __init __ (tự, chiều rộng, chiều cao):def __init__(self,width,height):

        self.width=widthself.width =width

        self.height=heightself.height=height

& nbsp; & nbsp; & nbsp; & nbsp; def get_area (self):def get_area(self):

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;return self.width *self.height

& nbsp; & nbsp; & nbsp; & nbsp; def set_width (self, width):def set_width(self,width):

        self.width=widthself.width=width

& nbsp; & nbsp; & nbsp; & nbsp; def set_height (tự, chiều cao):def set_height(self,height):

        self.height=heightself.height=height

# Chức năng kiểm tra được thực thi bởi pytest

DEF test_normal_case ():test_normal_case():

    rectangle=Rectangle(2,3)rectangle =Rectangle(2,3)

& nbsp; & nbsp; & nbsp; & nbsp; assertrectangle.get_area () == 6, "khu vực không chính xác"assertrectangle.get_area()==6,"incorrect area"

Bạn sẽ nhận thấy rằng Pytest sử dụng từ khóa assert tích hợp của Python, thay vì tập hợp các chức năng khẳng định của riêng nó như Pyunit, có thể giúp nó thuận tiện hơn một chút vì chúng tôi có thể tránh tìm kiếm các chức năng khẳng định khác nhau.

Mã hoàn chỉnh như sau:-mpytest test_file.py

# Mã của chúng tôi sẽ được kiểm tra

& nbsp; & nbsp; & nbsp; & nbsp; def __init __ (tự, chiều rộng, chiều cao):

& nbsp; & nbsp; & nbsp; & nbsp; def get_area (self):

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;

& nbsp; & nbsp; & nbsp; & nbsp; def set_width (self, width):

& nbsp; & nbsp; & nbsp; & nbsp; def set_height (tự, chiều cao):

# Chức năng kiểm tra được thực thi bởi pytest

DEF test_normal_case ():

Sau khi lưu điều này vào một tệp runTest()3, chúng ta có thể chạy thử nghiệm đơn vị pytest bằng cách:

Python-mpytest test_file.py

classTestGetAreaRectangle:TestGetAreaRectangle:

Và điều này cho chúng ta đầu ra:def test_normal_case(self):

        rectangle=Rectangle(2,3)rectangle=Rectangle(2,3)

=================== Phiên kiểm tra bắt đầu ==========================================assert rectangle.get_area()==6,"incorrect area"

Nền tảng Darwin-Python 3.9.9, Pytest-7.0.1, pluggy-1.0.0def test_negative_case(self):

rootdir: /user /mlm"""expect -1 as output to denote error when looking at negative area"""

        rectangle=Rectangle(-1,2)rectangle=Rectangle(-1,2)

plugin: Anyio-3.4.0, typeguard-2.13.2assertrectangle.get_area() ==-1,"incorrect negative output"

thu thập 1 mặt hàng

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

& nbsp; & nbsp; & nbsp; & nbsp; def __init __ (tự, chiều rộng, chiều cao):

& nbsp; & nbsp; & nbsp; & nbsp; def get_area (self):

rootdir: /user /mlm

plugin: Anyio-3.4.0, typeguard-2.13.2

thu thập 2 mặt hàng

test_code.py .f & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;

========================== Thất bại ======================== =

_________ TestGetAreeChectangle.test_negative_case __________

tự =

def test_negative_case (self):

"" "Mong đợi -1 là đầu ra để biểu thị lỗi khi nhìn vào vùng tiêu cực" ""

hình chữ nhật = hình chữ nhật (-1, 2)

> & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; khẳng định hình chữ nhật.get_area () == -1, "đầu ra âm không chính xác"

E & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; AssitSerError: Đầu ra âm không chính xác

E & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; khẳng định -2 == -1

E & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;+& nbsp; & nbsp; trong đó -2 = ()

E & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;+& nbsp;

unittest5.py:24: AssitSerror

================= Tóm tắt kiểm tra ngắn thông tin ===============================================

Thất bại test_code.py::TgetAleArectangle::Test_Negative_case

=============== 1 thất bại, 1 đã vượt qua trong 0,12S =============================================================

Mã hoàn chỉnh như sau:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

# Mã của chúng tôi sẽ được kiểm tra

classRectangle:Rectangle:

& nbsp; & nbsp; & nbsp; & nbsp; def __init __ (tự, chiều rộng, chiều cao):def __init__(self,width,height):

        self.width=widthself.width =width

        self.height=heightself.height=height

& nbsp; & nbsp; & nbsp; & nbsp; def get_area (self):def get_area(self):

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;return self.width *self.height

& nbsp; & nbsp; & nbsp; & nbsp; def set_width (self, width):def set_width(self,width):

        self.width=widthself.width=width

& nbsp; & nbsp; & nbsp; & nbsp; def set_height (tự, chiều cao):def set_height(self,height):

        self.height=heightself.height=height

# Các chức năng kiểm tra sẽ được thực hiện bởi pytest

classTestGetAreaRectangle:TestGetAreaRectangle:

& nbsp; & nbsp; & nbsp; & nbsp;def test_normal_case(self):

        rectangle=Rectangle(2,3)rectangle=Rectangle(2,3)

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;assert rectangle.get_area()==6,"incorrect area"

& nbsp; & nbsp; & nbsp; & nbsp;def test_negative_case(self):

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;"""expect -1 as output to denote error when looking at negative area"""

        rectangle=Rectangle(-1,2)rectangle=Rectangle(-1,2)

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;assertrectangle.get_area() ==-1,"incorrect negative output"

Để thực hiện mã thiết lập và phá vỡ cho các thử nghiệm của chúng tôi, PyTest có một hệ thống cố định cực kỳ linh hoạt, trong đó đồ đạc là các hàm có giá trị trả về. Hệ thống cố định Pytest cho phép chia sẻ đồ đạc trên các lớp, mô -đun, gói hoặc phiên và đồ đạc có thể gọi các đồ đạc khác là đối số.

Ở đây chúng tôi bao gồm một giới thiệu đơn giản về hệ thống cố định pytest nhất:

@pytest.fixturepytest.fixture

hình chữ nhật ():rectangle():

    returnRectangle(0,0)returnRectangle(0,0)

DEC TEST_NEGIATION_CASE (Hình chữ nhật):test_negative_case(rectangle):

    print(rectangle.width)print (rectangle.width)

    rectangle.set_width(-1)rectangle.set_width(-1)

    rectangle.set_height(2)rectangle.set_height(2)

& nbsp; & nbsp; & nbsp; & nbsp; assertrectangle.get_area () ==-1, "Đầu ra âm không chính xác"assert rectangle.get_area()==-1,"incorrect negative output"

Mã trên giới thiệu hình chữ nhật như một vật cố định và pytest khớp với hình chữ nhật trong danh sách đối số của unittest7 với vật cố và cung cấp unittest7 với bộ đầu ra riêng từ hàm hình chữ nhật. Nó làm điều này cho mọi bài kiểm tra khác. Tuy nhiên, lưu ý rằng các đồ đạc có thể được yêu cầu nhiều lần cho mỗi lần thử và cho mỗi thử nghiệm, vật cố chỉ được chạy một lần và kết quả được lưu trữ. Điều này có nghĩa là tất cả các tài liệu tham khảo về trận đấu đó trong quá trình chạy thử nghiệm riêng lẻ đang tham khảo cùng một giá trị trả về (điều này rất quan trọng nếu giá trị trả về là loại tham chiếu).

Mã hoàn chỉnh như sau:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

# Mã của chúng tôi sẽ được kiểm trapytest

# Mã của chúng tôi sẽ được kiểm tra

classRectangle:Rectangle:

& nbsp; & nbsp; & nbsp; & nbsp; def __init __ (tự, chiều rộng, chiều cao):def __init__(self,width,height):

        self.width=widthself.width =width

        self.height=heightself.height=height

& nbsp; & nbsp; & nbsp; & nbsp; def get_area (self):def get_area(self):

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;return self.width *self.height

& nbsp; & nbsp; & nbsp; & nbsp; def set_width (self, width):def set_width(self,width):

        self.width=widthself.width=width

& nbsp; & nbsp; & nbsp; & nbsp; def set_height (tự, chiều cao):def set_height(self,height):

        self.height=heightself.height=height

@pytest.fixturepytest.fixture

hình chữ nhật ():rectangle():

    returnRectangle(0,0)return Rectangle(0,0)

DEC TEST_NEGIATION_CASE (Hình chữ nhật):test_negative_case(rectangle):

    print(rectangle.width)print(rectangle.width)

    rectangle.set_width(-1)rectangle.set_width(-1)

    rectangle.set_height(2)rectangle.set_height(2)

& nbsp; & nbsp; & nbsp; & nbsp; assertrectangle.get_area () ==-1, "Đầu ra âm không chính xác"assertrectangle.get_area()==-1,"incorrect negative output"

Giống như Pyunit, Pytest có rất nhiều chức năng khác cho phép bạn xây dựng các bài kiểm tra đơn vị toàn diện và nâng cao hơn.

Kiểm tra đơn vị trong hành động

Bây giờ, chúng tôi sẽ khám phá thử nghiệm đơn vị trong hành động. Ví dụ của chúng tôi, chúng tôi sẽ thử nghiệm một chức năng nhận dữ liệu chứng khoán từ Yahoo Finance bằng cách sử dụng unittest.TestCase0 và thực hiện việc này trong Pyunit:

Nhập pandas_datareader.data aswebpandas_datareader.data asweb

def get_stock_data (ticker):get_stock_data(ticker):

& nbsp; & nbsp; & nbsp; & nbsp; "" "" Kéo dữ liệu từ stooq "" """"pull data from stooq"""

    df=web.DataReader(ticker,"yahoo")df= web.DataReader(ticker,"yahoo")

    returndfreturndf

Chức năng này nhận được dữ liệu cổ phiếu trên một mã ve cổ phiếu cụ thể bằng cách thu thập dữ liệu từ trang web của Yahoo Finance và trả về Pandas DataFrame. Điều này có thể thất bại theo nhiều cách. Ví dụ: đầu đọc dữ liệu có thể không trả lại bất cứ điều gì (nếu tài chính Yahoo bị giảm) hoặc trả về DataFrame với các cột bị thiếu hoặc thiếu dữ liệu trong các cột (nếu nguồn được cơ cấu lại trang web của nó). Do đó, chúng tôi nên cung cấp nhiều chức năng kiểm tra để kiểm tra nhiều chế độ thất bại:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

Nhập dữ liệudatetime

Nhập khẩu Unittestunittest

Nhập Pandas ASPDpandas aspd

Nhập pandas_datareader.data aswebpandas_datareader.data asweb

def get_stock_data (ticker):get_stock_data(ticker):

& nbsp; & nbsp; & nbsp; & nbsp; "" "" Kéo dữ liệu từ stooq "" """"pull data from stooq"""

    df=web.DataReader(ticker,'yahoo')df=web.DataReader(ticker,'yahoo')

    returndfreturndf

classTestGetStockData(unittest.TestCase): TestGetStockData(unittest.TestCase):

    @classmethod@classmethod

Chức năng này nhận được dữ liệu cổ phiếu trên một mã ve cổ phiếu cụ thể bằng cách thu thập dữ liệu từ trang web của Yahoo Finance và trả về Pandas DataFrame. Điều này có thể thất bại theo nhiều cách. Ví dụ: đầu đọc dữ liệu có thể không trả lại bất cứ điều gì (nếu tài chính Yahoo bị giảm) hoặc trả về DataFrame với các cột bị thiếu hoặc thiếu dữ liệu trong các cột (nếu nguồn được cơ cấu lại trang web của nó). Do đó, chúng tôi nên cung cấp nhiều chức năng kiểm tra để kiểm tra nhiều chế độ thất bại:def setUpClass(self):

Nhập dữ liệu"""We only want to pull this data once for each TestCase since it is an expensive operation"""

        self.df=get_stock_data('^DJI')self.df=get_stock_data('^DJI')

Nhập khẩu Unittestdef test_columns_present(self):

Nhập Pandas ASPD"""ensures that the expected columns are all present"""

        self.assertIn("Open",self.df.columns)self.assertIn("Open",self.df.columns)

        self.assertIn("High",self.df.columns)self.assertIn("High", self.df.columns)

        self.assertIn("Low",self.df.columns)self.assertIn("Low",self.df.columns)

        self.assertIn("Close",self.df.columns)self.assertIn("Close", self.df.columns)

        self.assertIn("Volume",self.df.columns)self.assertIn("Volume",self.df.columns)

& nbsp; & nbsp; & nbsp; & nbsp; def setuplass (self):def test_non_empty(self):

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;"""ensures that there is more than one row of data"""

        self.assertNotEqual(len(self.df.index),0)self.assertNotEqual(len(self.df.index), 0)

& nbsp;def test_high_low(self):

& nbsp;"""ensure high and low are the highest and lowest in the same row"""

        ohlc=self.df[["Open","High","Low","Close"]]ohlc= self.df[["Open","High","Low","Close"]]

        highest=ohlc.max(axis=1)highest=ohlc.max(axis=1)

        lowest=ohlc.min(axis=1)lowest =ohlc.min(axis=1)

        self.assertTrue(ohlc.le(highest,axis=0).all(axis=None))self.assertTrue(ohlc.le(highest, axis=0).all(axis=None))

        self.assertTrue(ohlc.ge(lowest,axis=0).all(axis=None))self.assertTrue(ohlc.ge(lowest, axis=0).all(axis=None))

& nbsp; & nbsp; & nbsp; & nbsp;def test_most_recent_within_week(self):

& nbsp;"""most recent data was collected within the last week"""

        most_recent_date=pd.to_datetime(self.df.index[-1])most_recent_date=pd.to_datetime(self.df.index[-1])

        self.assertLessEqual((datetime.datetime.today()-most_recent_date).days,7)self.assertLessEqual((datetime.datetime.today() -most_recent_date).days,7)

unittest.main().main()

& nbsp; & nbsp; & nbsp; & nbsp;

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;

& nbsp; & nbsp; & nbsp; & nbsp;

Để hoàn thiện, ở đây, một phiên bản tương đương cho pytest:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

nhập khẩu pytestpytest

# scope = "class" đã rơi xuống trận đấu ở cuối bài kiểm tra cuối cùng trong lớp, vì vậy chúng tôi tránh chạy lại bước này.

@pytest.fixture(scope="class")pytest.fixture(scope="class")

def stock_df ():stock_df():

& nbsp; & nbsp;# Chúng tôi chỉ muốn lấy dữ liệu này một lần cho mỗi trường hợp Testcase vì nó là một hoạt động đắt tiền# We only want to pull this data once for each TestCase since it is an expensive operation

  df=get_stock_data('^DJI')df=get_stock_data('^DJI')

  returndfreturndf

classTestGetStockData:TestGetStockData:

& nbsp; & nbsp; DEC test_columns_present (self, stock_df):def test_columns_present(self,stock_df):

& nbsp; & nbsp; & nbsp; & nbsp;# đảm bảo rằng các cột dự kiến ​​đều có mặt# ensures that the expected columns are all present

    assert"Open"instock_df.columnsassert"Open"instock_df.columns

    assert"High"instock_df.columnsassert "High"instock_df.columns

    assert"Low"instock_df.columnsassert"Low"instock_df.columns

    assert"Close"instock_df.columnsassert"Close"in stock_df.columns

    assert"Volume"instock_df.columnsassert"Volume"instock_df.columns

& nbsp; & nbsp; def test_non_empty (self, stock_df):def test_non_empty(self,stock_df):

& nbsp; & nbsp; & nbsp; & nbsp;# đảm bảo rằng có nhiều hơn một hàng dữ liệu# ensures that there is more than one row of data

    assertlen(stock_df.index)!=0assertlen(stock_df.index)!=0

& nbsp; & nbsp; def test_est_recent_within_week (self, stock_df):def test_most_recent_within_week(self,stock_df):

& nbsp; & nbsp; & nbsp; & nbsp;# dữ liệu gần đây nhất được thu thập trong tuần trước# most recent data was collected within the last week

    most_recent_date=pd.to_datetime(stock_df.index[0])most_recent_date=pd.to_datetime(stock_df.index[0])

    assert(datetime.datetime.today()-most_recent_date).daysassert (datetime.datetime.today()-most_recent_date).days<=7

Các bài kiểm tra đơn vị xây dựng có vẻ tốn thời gian và tẻ nhạt, nhưng chúng có thể là một phần quan trọng của bất kỳ đường ống CI nào và là công cụ vô giá để bắt lỗi sớm trước khi chúng di chuyển xuống đường ống và trở nên tốn kém hơn để giải quyết.

Nếu bạn thích nó thì bạn nên đặt một bài kiểm tra về nó.

- Kỹ thuật phần mềm tại Google

Đọc thêm

Phần này cung cấp nhiều tài nguyên hơn về chủ đề nếu bạn đang muốn đi sâu hơn.

Thư viện

  • Mô -đun Unittest (và danh sách các phương thức Assert), https://docs.python.org/3/l Library/unittest.html
  • Pytest, https://docs.pytest.org/en/7.0.x/

Bài viết

  • Phát triển theo hướng kiểm tra (TDD), https://www.ibm.com/garage/method/practices/code/practice_test_driven_development/
  • Khung kiểm tra đơn vị Python, http://pyunit.sourceforge.net/pyunit.html

Sách

  • Kỹ thuật phần mềm tại Google, bởi Titus Winters, Tom Manshreck và Hyrum Wright https://www.amazon.com/dp/1492082791
  • Thực hành lập trình, bởi Brian Kernighan và Rob Pike (Chương 5 và 6), https://www.amazon.com/dp/020161586x

Bản tóm tắt

Trong bài đăng này, bạn đã phát hiện ra thử nghiệm đơn vị là gì và cách sử dụng hai thư viện phổ biến trong Python để tiến hành thử nghiệm đơn vị (Pyunit, pytest). Bạn cũng đã học được cách định cấu hình các bài kiểm tra đơn vị và đã thấy một ví dụ về trường hợp sử dụng để kiểm tra đơn vị trong đường ống khoa học dữ liệu.

Cụ thể, bạn đã học được:

  • Kiểm tra đơn vị là gì và tại sao nó hữu ích
  • Cách kiểm tra đơn vị phù hợp với đường ống phát triển theo hướng thử nghiệm
  • Cách thực hiện kiểm tra đơn vị trong Python bằng cách sử dụng pyunit và pytest

Nhận một xử lý trên Python để học máy!

Hướng dẫn how unit testing is done in python? - cách kiểm tra đơn vị được thực hiện trong python?

Tự tin hơn để viết mã trong Python

... Từ việc học các thủ thuật trăn thực tế

Khám phá cách trong ebook mới của tôi: Python cho học máy
Python for Machine Learning

Nó cung cấp các hướng dẫn tự học với hàng trăm mã làm việc để trang bị cho bạn các kỹ năng bao gồm: gỡ lỗi, hồ sơ, gõ vịt, trang trí, triển khai, và nhiều hơn nữa ...self-study tutorials with hundreds of working code to equip you with skills including:
debugging, profiling, duck typing, decorators, deployment, and much more...

Cho bạn xem hộp công cụ Python ở mức cao cho các dự án của bạn
Your Projects

Xem những gì bên trong

Làm thế nào để bạn viết một bài kiểm tra đơn vị trong ví dụ Python?

Nguồn ví dụ thử nghiệm đơn vị Python Trước hết chúng ta phải viết một số mã để kiểm tra đơn vị chúng.Chúng tôi sẽ có một lớp Python.Mục đích chính của lớp là lưu trữ và truy xuất tên của người.Vì vậy, chúng tôi viết hàm set_name () để lưu trữ hàm dữ liệu và get_name () để truy xuất tên từ lớp.write set_name() function to store the data and get_name() function to retrieve name from the class.

Kiểm tra đơn vị được thực hiện như thế nào?

Một bài kiểm tra đơn vị thường bao gồm ba giai đoạn: kế hoạch, trường hợp và kịch bản và chính bài kiểm tra đơn vị.Trong bước đầu tiên, bài kiểm tra đơn vị được chuẩn bị và xem xét. Bước tiếp theo là các trường hợp kiểm tra và tập lệnh được thực hiện, sau đó mã được kiểm tra.In the first step, the unit test is prepared and reviewed. The next step is for the test cases and scripts to be made, then the code is tested.

Các công cụ kiểm tra đơn vị cho Python là gì?

Top 6 Khung thử nghiệm Python tốt nhất [Danh sách cập nhật 2022]..
So sánh các công cụ thử nghiệm Python ..
#1) Robot ..
#2) bytest ..
#3) Unittest ..
#4) Doctest ..
#5) Mũi2 ..
#6) làm chứng ..
Khung thử nghiệm Python bổ sung ..