Hướng dẫn dùng pytest django python



Các khóa học miễn phí qua video:
Lập trình C Java SQL Server PHP HTML5-CSS3-JavaScript

Mục lục bài viết:

  • Cách cài đặt pytest
  • Điều gì làm cho pytest trở nên hữu ích?
    • Ít Boilerplate
    • Quản lý Nhà nước và Sự phụ thuộc
    • Kiểm tra lọc
    • Kiểm tra tham số
    • Kiến trúc dựa trên plugin
  • Đồ đạc: Quản lý trạng thái và sự phụ thuộc
    • Khi nào tạo đồ đạc
    • Khi nào cần tránh đồ đạc
    • Đồ đạc ở quy mô
  • Marks: Phân loại Kiểm tra
  • Tham số hóa: Kết hợp các bài kiểm tra
  • Báo cáo thời lượng: Chiến đấu với các bài kiểm tra chậm
  • Plugin pytest hữu ích
    • pytest-ngẫu nhiên
    • pytest-cov
    • pytest-django
    • pytest-bdd
  • Phần kết luận


Kiểm tra mã của bạn mang lại nhiều lợi ích. Nó làm tăng sự tự tin của bạn rằng mã hoạt động như bạn mong đợi và đảm bảo rằng những thay đổi đối với mã của bạn sẽ không gây ra hồi quy. Viết và duy trì các bài kiểm tra là công việc khó khăn, vì vậy bạn nên tận dụng tất cả các công cụ theo ý của mình để làm cho nó dễ dàng nhất có thể. pytestlà một trong những công cụ tốt nhất mà bạn có thể sử dụng để tăng năng suất thử nghiệm của mình.

Trong hướng dẫn này, bạn sẽ học:

  • Những lợi ích pytest mang lại
  • Cách đảm bảo các bài kiểm tra của bạn là không trạng thái
  • Cách làm cho các bài kiểm tra lặp đi lặp lại dễ hiểu hơn
  • Cách chạy các tập con kiểm tra theo tên hoặc nhóm tùy chỉnh
  • Cách tạo và duy trì các tiện ích thử nghiệm có thể tái sử dụng

Cài đặt thế nào pytest

Để làm theo một số ví dụ trong hướng dẫn này, bạn cần cài đặt pytest. Như với hầu hết các gói Python , bạn có thể cài đặt pytesttrong môi trường ảo từ PyPI bằng cách sử dụng pip:

$ python -m pip install pytest

Các pytestlệnh bây giờ sẽ có sẵn trong môi trường cài đặt của bạn.

Điều gì làm nên pytesthữu ích?

Nếu bạn đã viết các bài kiểm tra đơn vị cho mã Python của mình trước đây, thì bạn có thể đã sử dụng unittestmô-đun tích hợp sẵn của Python . unittestcung cấp một cơ sở vững chắc để xây dựng bộ thử nghiệm của bạn, nhưng nó có một vài thiếu sót.

Một số khuôn khổ thử nghiệm của bên thứ ba cố gắng giải quyết một số vấn đề unittestvà pytestđã được chứng minh là một trong những khuôn khổ phổ biến nhất . pytestlà một hệ sinh thái dựa trên plugin, giàu tính năng để kiểm tra mã Python của bạn.

Nếu bạn chưa cảm thấy thích thú khi sử dụng pytest, thì bạn sẽ được thưởng thức! Triết lý và các tính năng của nó sẽ làm cho trải nghiệm thử nghiệm của bạn hiệu quả và thú vị hơn. Với pytest, các tác vụ thông thường yêu cầu ít mã hơn và các tác vụ nâng cao có thể đạt được thông qua nhiều lệnh và plugin tiết kiệm thời gian. Nó thậm chí sẽ chạy các bài kiểm tra hiện có của bạn ra khỏi hộp, bao gồm cả những bài kiểm tra được viết bằng unittest.

Như với hầu hết các khuôn khổ, một số mẫu phát triển có ý nghĩa khi bạn mới bắt đầu sử dụng pytestcó thể bắt đầu gây ra khó khăn khi bộ thử nghiệm của bạn phát triển. Hướng dẫn này sẽ giúp bạn hiểu một số công cụ pytestcung cấp để giữ cho thử nghiệm của bạn hiệu quả và hiệu quả ngay cả khi nó mở rộng quy mô.

Ít Boilerplate

Hầu hết các thử nghiệm chức năng tuân theo mô hình Sắp xếp-Hành động-Khẳng định:

  1. Sắp xếp hoặc thiết lập các điều kiện cho bài kiểm tra
  2. Hành động bằng cách gọi một số hàm hoặc phương thức
  3. Khẳng định rằng một số điều kiện cuối cùng là đúng

Các khuôn khổ thử nghiệm thường kết hợp với các xác nhận trong thử nghiệm của bạn để chúng có thể cung cấp thông tin khi một xác nhận không thành công. unittest, ví dụ, cung cấp một số tiện ích xác nhận hữu ích ngay lập tức. Tuy nhiên, ngay cả một tập hợp nhỏ các bài kiểm tra cũng yêu cầu một lượng mã bản ghi sẵn .

Hãy tưởng tượng bạn muốn viết một bộ thử nghiệm chỉ để đảm bảo rằng unittestdự án của bạn đang hoạt động bình thường. Bạn có thể muốn viết một bài kiểm tra luôn vượt qua và một bài kiểm tra luôn không thành công:

# test_with_unittest.py

from unittest import TestCase

class TryTesting(TestCase):
    def test_always_passes(self):
        self.assertTrue(True)

    def test_always_fails(self):
        self.assertTrue(False)

Sau đó, bạn có thể chạy các bài kiểm tra đó từ dòng lệnh bằng cách sử dụng discovertùy chọn unittest:

$ python -m unittest discover
F.
============================================================
FAIL: test_always_fails (test_with_unittest.TryTesting)
------------------------------------------------------------
Traceback (most recent call last):
  File "/.../test_with_unittest.py", line 9, in test_always_fails
    self.assertTrue(False)
AssertionError: False is not True

------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (failures=1)

Đúng như dự đoán, một bài kiểm tra đã vượt qua và một bài thi không đạt. Bạn đã chứng minh rằng điều đó unittestđang hoạt động, nhưng hãy nhìn vào những gì bạn phải làm:

  1. Nhập TestCaselớp từunittest
  2. Tạo TryTesting, một lớp con củaTestCase
  3. Viết một phương thức TryTestingcho mỗi bài kiểm tra
  4. Sử dụng một trong các self.assert*phương pháp từ unittest.TestCaseđể đưa ra khẳng định

Đó là một lượng mã đáng kể để viết và vì đó là số lượng tối thiểu bạn cần cho bất kỳ bài kiểm tra nào , nên bạn sẽ phải viết đi viết lại cùng một mã. pytestđơn giản hóa quy trình làm việc này bằng cách cho phép bạn sử dụng asserttrực tiếp từ khóa của Python :

# test_with_pytest.py

def test_always_passes():
    assert True

def test_always_fails():
    assert False

Đó là nó. Bạn không phải đối phó với bất kỳ nhập khẩu hoặc lớp nào. Bởi vì bạn có thể sử dụng asserttừ khóa, bạn cũng không cần phải học hoặc nhớ tất cả các self.assert*phương pháp khác nhau unittest. Nếu bạn có thể viết một biểu thức mà bạn mong đợi để đánh giá True, sau đó pytestsẽ kiểm tra nó cho bạn. Bạn có thể chạy nó bằng pytestlệnh:

$ pytest
================== test session starts =============================
platform darwin -- Python 3.7.3, pytest-5.3.0, py-1.8.0, pluggy-0.13.0
rootdir: /.../effective-python-testing-with-pytest
collected 2 items

test_with_pytest.py .F                                          [100%]

======================== FAILURES ==================================
___________________ test_always_fails ______________________________

    def test_always_fails():
>       assert False
E       assert False

test_with_pytest.py:5: AssertionError
============== 1 failed, 1 passed in 0.07s =========================

pytesttrình bày kết quả thử nghiệm khác với unittest. Báo cáo cho thấy:

  1. Trạng thái hệ thống, bao gồm phiên bản Python pytestvà bất kỳ plugin nào bạn đã cài đặt
  2. Các rootdirhoặc thư mục để tìm kiếm dưới để cấu hình và kiểm tra
  3. Số lượng bài kiểm tra mà người chạy đã phát hiện

Sau đó, đầu ra cho biết trạng thái của mỗi bài kiểm tra bằng cách sử dụng cú pháp tương tự như unittest:

  • Dấu chấm ( .) có nghĩa là bài kiểm tra đã vượt qua.
  • AnF có nghĩa là bài kiểm tra đã không thành công.
  • AnE có nghĩa là bài kiểm tra đã nêu ra một ngoại lệ không mong muốn.

Đối với các thử nghiệm không đạt, báo cáo đưa ra bảng phân tích chi tiết về lỗi. Trong ví dụ trên, kiểm tra không thành công vì assert Falseluôn thất bại. Cuối cùng, báo cáo đưa ra một báo cáo trạng thái tổng thể của bộ thử nghiệm.

Dưới đây là một số ví dụ khẳng định nhanh hơn:

def test_uppercase():
    assert "loud noises".upper() == "LOUD NOISES"

def test_reversed():
    assert list(reversed([1, 2, 3, 4])) == [4, 3, 2, 1]

def test_some_primes():
    assert 37 in {
        num
        for num in range(1, 50)
        if num != 1 and not any([num % div == 0 for div in range(2, num)])
    }

Đường cong học tập cho pytestlà nông hơn so với unittestvì bạn không cần phải học các cấu trúc mới cho hầu hết các bài kiểm tra. Ngoài ra, việc sử dụng assert, mà bạn có thể đã sử dụng trước đây trong mã triển khai của mình, làm cho các thử nghiệm của bạn dễ hiểu hơn.

Quản lý Nhà nước và Sự phụ thuộc

Các bài kiểm tra của bạn thường sẽ phụ thuộc vào các phần dữ liệu hoặc kiểm tra gấp đôi cho một số đối tượng trong mã của bạn. Trong unittest, bạn có thể trích xuất các phần phụ thuộc này vào setUp()và tearDown()các phương thức để mỗi bài kiểm tra trong lớp có thể sử dụng chúng. Nhưng khi làm như vậy, bạn có thể vô tình làm cho sự phụ thuộc của bài kiểm tra vào một phần dữ liệu hoặc đối tượng cụ thể là hoàn toàn tiềm ẩn .

Theo thời gian, các phụ thuộc ngầm định có thể dẫn đến một mớ mã phức tạp mà bạn phải giải nén để hiểu các bài kiểm tra của mình. Các bài kiểm tra sẽ giúp bạn làm cho mã của mình dễ hiểu hơn. Nếu bản thân các bài kiểm tra khó hiểu, thì bạn có thể gặp rắc rối!

pytestcó một cách tiếp cận khác. Nó dẫn bạn đến các khai báo phụ thuộc rõ ràng mà vẫn có thể sử dụng lại nhờ vào sự sẵn có của các thiết bị cố định . pytestfixtures là các chức năng tạo dữ liệu hoặc kiểm tra nhân đôi hoặc khởi tạo một số trạng thái hệ thống cho bộ thử nghiệm. Bất kỳ thử nghiệm nào muốn sử dụng một vật cố định phải chấp nhận rõ ràng nó như một đối số, vì vậy các phụ thuộc luôn được nêu trước.

Các đồ đạc cũng có thể sử dụng các đồ đạc khác, một lần nữa bằng cách khai báo chúng một cách rõ ràng dưới dạng phụ thuộc. Điều đó có nghĩa là, theo thời gian, đồ đạc của bạn có thể trở nên cồng kềnh và mô đun. Mặc dù khả năng chèn đồ đạc vào các đồ đạc khác cung cấp tính linh hoạt rất lớn, nhưng nó cũng có thể khiến việc quản lý các phần phụ thuộc trở nên khó khăn hơn khi bộ thử nghiệm của bạn phát triển. Phần sau của hướng dẫn này, bạn sẽ tìm hiểu thêm về đồ đạc và thử một vài kỹ thuật để xử lý những thách thức này.

Kiểm tra lọc

Khi bộ thử nghiệm của bạn phát triển, bạn có thể thấy rằng bạn chỉ muốn chạy một vài thử nghiệm trên một tính năng và lưu bộ đầy đủ để sử dụng sau này. pytestcung cấp một số cách để thực hiện việc này:

  • Lọc dựa trên tên : Bạn có thể giới hạn pytestchỉ chạy những bài kiểm tra có tên đủ điều kiện phù hợp với một biểu thức cụ thể. Bạn có thể làm điều này với -ktham số.
  • Phạm vi thư mục : Theo mặc định, pytestsẽ chỉ chạy những thử nghiệm nằm trong hoặc dưới thư mục hiện tại.
  • Phân loại thử nghiệm : pytestcó thể bao gồm hoặc loại trừ các thử nghiệm khỏi các danh mục cụ thể mà bạn xác định. Bạn có thể làm điều này với -mtham số.

Phân loại thử nghiệm nói riêng là một công cụ mạnh mẽ một cách tinh vi. pytestcho phép bạn tạo nhãn hiệu hoặc nhãn tùy chỉnh cho bất kỳ bài kiểm tra nào bạn muốn. Một bài kiểm tra có thể có nhiều nhãn và bạn có thể sử dụng chúng để kiểm soát chi tiết những bài kiểm tra nào sẽ chạy. Phần sau của hướng dẫn này, bạn sẽ thấy một ví dụ về cách thức pytesthoạt động của điểm và tìm hiểu cách sử dụng chúng trong một bộ thử nghiệm lớn.

Kiểm tra tham số

Khi bạn đang thử nghiệm các chức năng xử lý dữ liệu hoặc thực hiện các phép biến đổi chung, bạn sẽ thấy mình đang viết nhiều thử nghiệm tương tự. Chúng chỉ có thể khác nhau về đầu vào hoặc đầu ra của mã đang được kiểm tra. Điều này yêu cầu sao chép mã kiểm tra và làm như vậy đôi khi có thể che khuất hành vi bạn đang cố gắng kiểm tra.

unittestcung cấp một cách thu thập một số bài kiểm tra thành một, nhưng chúng không hiển thị dưới dạng các bài kiểm tra riêng lẻ trong báo cáo kết quả. Nếu một bài kiểm tra không đạt và phần còn lại vượt qua, thì toàn bộ nhóm sẽ vẫn trả về một kết quả không đạt. pytestđưa ra giải pháp riêng trong đó mỗi bài kiểm tra có thể vượt qua hoặc thất bại một cách độc lập. Bạn sẽ thấy làm thế nào để parametrize kiểm tra với pytestsau này trong hướng dẫn này.

Kiến trúc dựa trên plugin

Một trong những tính năng đẹp nhất của pytestnó là khả năng tùy biến và các tính năng mới. Hầu hết mọi phần của chương trình đều có thể được bẻ khóa và thay đổi. Kết quả là, pytestngười dùng đã phát triển một hệ sinh thái phong phú gồm các plugin hữu ích.

Mặc dù một số pytestplugin tập trung vào các khuôn khổ cụ thể như Django , các plugin khác có thể áp dụng cho hầu hết các bộ thử nghiệm. Bạn sẽ thấy chi tiết về một số plugin cụ thể sau trong hướng dẫn này.

Đồ đạc: Quản lý trạng thái và sự phụ thuộc

pytestđồ đạc là một cách cung cấp dữ liệu, bộ đôi kiểm tra hoặc thiết lập trạng thái cho các bài kiểm tra của bạn. Fixtures là các hàm có thể trả về một loạt các giá trị. Mỗi thử nghiệm phụ thuộc vào một vật cố định phải chấp nhận rõ ràng vật cố định đó như một đối số.

Khi nào tạo đồ đạc

Hãy tưởng tượng bạn đang viết một hàm format_data_for_display(), để xử lý dữ liệu được trả về bởi một điểm cuối API. Dữ liệu đại diện cho một danh sách những người, mỗi người có một tên cụ thể, họ và chức danh công việc. Hàm sẽ xuất ra một danh sách các chuỗi bao gồm tên đầy đủ của mỗi người ( given_nametheo sau là của họ family_name), dấu hai chấm và của họ title. Để kiểm tra điều này, bạn có thể viết mã sau:

def format_data_for_display(people):
    ...  # Implement this!

def test_format_data_for_display():
    people = [
        {
            "given_name": "Alfonsa",
            "family_name": "Ruiz",
            "title": "Senior Software Engineer",
        },
        {
            "given_name": "Sayid",
            "family_name": "Khan",
            "title": "Project Manager",
        },
    ]

    assert format_data_for_display(people) == [
        "Alfonsa Ruiz: Senior Software Engineer",
        "Sayid Khan: Project Manager",
    ]

Bây giờ, giả sử bạn cần viết một hàm khác để chuyển đổi dữ liệu thành các giá trị được phân tách bằng dấu phẩy để sử dụng trong Excel . Bài kiểm tra sẽ trông rất giống nhau:

def format_data_for_excel(people):
    ... # Implement this!

def test_format_data_for_excel():
    people = [
        {
            "given_name": "Alfonsa",
            "family_name": "Ruiz",
            "title": "Senior Software Engineer",
        },
        {
            "given_name": "Sayid",
            "family_name": "Khan",
            "title": "Project Manager",
        },
    ]

    assert format_data_for_excel(people) == """given,family,title
Alfonsa,Ruiz,Senior Software Engineer
Sayid,Khan,Project Manager
"""

Nếu bạn thấy mình đang viết một số bài kiểm tra mà tất cả đều sử dụng cùng một dữ liệu kiểm tra cơ bản, thì tương lai của bạn có thể sẽ có một lịch thi đấu. Bạn có thể kéo dữ liệu lặp lại vào một hàm duy nhất được trang trí bằng @pytest.fixtuređể chỉ ra rằng hàm là một pytestvật cố định:

import pytest

@pytest.fixture
def example_people_data():
    return [
        {
            "given_name": "Alfonsa",
            "family_name": "Ruiz",
            "title": "Senior Software Engineer",
        },
        {
            "given_name": "Sayid",
            "family_name": "Khan",
            "title": "Project Manager",
        },
    ]

Bạn có thể sử dụng vật cố định bằng cách thêm nó làm đối số cho các bài kiểm tra của mình. Giá trị của nó sẽ là giá trị trả về của hàm fixture:

def test_format_data_for_display(example_people_data):
    assert format_data_for_display(example_people_data) == [
        "Alfonsa Ruiz: Senior Software Engineer",
        "Sayid Khan: Project Manager",
    ]

def test_format_data_for_excel(example_people_data):
    assert format_data_for_excel(example_people_data) == """given,family,title
Alfonsa,Ruiz,Senior Software Engineer
Sayid,Khan,Project Manager
"""

Mỗi bài kiểm tra giờ đây ngắn hơn đáng kể nhưng vẫn có một đường dẫn rõ ràng trở lại dữ liệu mà nó phụ thuộc vào. Hãy chắc chắn đặt tên cho vật cố định của bạn một cái gì đó cụ thể. Bằng cách đó, bạn có thể nhanh chóng xác định xem bạn có muốn sử dụng nó khi viết các bài kiểm tra mới trong tương lai hay không!

Khi nào cần tránh đồ đạc

Các đồ đạc rất tuyệt vời để trích xuất dữ liệu hoặc các đối tượng mà bạn sử dụng trong nhiều thử nghiệm. Chúng không phải lúc nào cũng tốt cho các thử nghiệm yêu cầu sự thay đổi nhỏ trong dữ liệu. Rải rác bộ thử nghiệm của bạn với các thiết bị cố định không tốt hơn là xả rác với dữ liệu hoặc đối tượng thuần túy. Nó thậm chí có thể tồi tệ hơn vì có thêm lớp hướng dẫn.

Như với hầu hết các bản tóm tắt, cần phải thực hành và suy nghĩ để tìm ra mức độ sử dụng vật cố định phù hợp.

Đồ đạc ở quy mô

Khi bạn trích xuất nhiều đồ đạc hơn từ các thử nghiệm của mình, bạn có thể thấy rằng một số đồ đạc có thể được hưởng lợi từ việc trích xuất thêm. Đồ đạc có dạng mô-đun , vì vậy chúng có thể phụ thuộc vào đồ đạc khác. Bạn có thể thấy rằng các đồ đạc trong hai mô-đun thử nghiệm riêng biệt có chung một sự phụ thuộc. Bạn có thể làm gì trong trường hợp này?

Bạn có thể di chuyển đồ đạc từ các mô-đun thử nghiệm sang các mô-đun liên quan đến vật cố định tổng quát hơn. Bằng cách đó, bạn có thể nhập chúng trở lại vào bất kỳ mô-đun thử nghiệm nào cần chúng. Đây là một cách tiếp cận tốt khi bạn thấy mình sử dụng một vật cố định lặp đi lặp lại trong suốt dự án của mình.

pytesttìm kiếm conftest.pycác mô-đun trong toàn bộ cấu trúc thư mục. Mỗi conftest.pycung cấp cấu hình cho cây tệp pytesttìm thấy nó. Bạn có thể sử dụng bất kỳ đồ đạc nào được xác định cụ thể conftest.pytrong suốt thư mục mẹ của tệp và trong bất kỳ thư mục con nào. Đây là một nơi tuyệt vời để đặt các đồ đạc được sử dụng rộng rãi nhất của bạn.

Một trường hợp sử dụng thú vị khác cho đồ đạc là bảo vệ quyền truy cập vào tài nguyên. Hãy tưởng tượng rằng bạn đã viết một bộ thử nghiệm cho mã xử lý các lệnh gọi API . Bạn muốn đảm bảo rằng bộ thử nghiệm không thực hiện bất kỳ cuộc gọi mạng thực nào, ngay cả khi một thử nghiệm vô tình thực thi mã cuộc gọi mạng thực. pytestcung cấp một monkeypatchvật cố định để thay thế các giá trị và hành vi mà bạn có thể sử dụng để tạo ra hiệu quả tuyệt vời:

# conftest.py

import pytest
import requests

@pytest.fixture(autouse=True)
def disable_network_calls(monkeypatch):
    def stunted_get():
        raise RuntimeError("Network access not allowed during testing!")
    monkeypatch.setattr(requests, "get", lambda *args, **kwargs: stunted_get())

Bằng cách đặt disable_network_calls()trong conftest.pyvà thêm các autouse=Truetùy chọn, bạn đảm bảo rằng các cuộc gọi mạng sẽ bị vô hiệu trong mọi thử nghiệm trên toàn bộ các. Bất kỳ thử nghiệm nào thực hiện cuộc gọi mã requests.get()sẽ đưa RuntimeErrorra dấu hiệu rằng một cuộc gọi mạng không mong muốn đã xảy ra.

Marks: Phân loại Kiểm tra

Trong bất kỳ bộ thử nghiệm lớn nào, một số thử nghiệm chắc chắn sẽ bị chậm. Ví dụ: họ có thể kiểm tra hành vi hết thời gian chờ hoặc họ có thể thực hiện một vùng rộng của mã. Dù lý do là gì, sẽ rất tốt nếu bạn tránh chạy tất cả các bài kiểm tra chậm khi bạn đang cố gắng lặp lại nhanh chóng trên một tính năng mới.

pytestcho phép bạn xác định các danh mục cho các thử nghiệm của mình và cung cấp các tùy chọn để bao gồm hoặc loại trừ các danh mục khi bạn chạy bộ của mình. Bạn có thể chấm một bài kiểm tra với bất kỳ số hạng mục nào.

Đánh dấu các bài kiểm tra rất hữu ích cho việc phân loại các bài kiểm tra theo hệ thống con hoặc phụ thuộc. Ví dụ: nếu một số bài kiểm tra của bạn yêu cầu quyền truy cập vào cơ sở dữ liệu, thì bạn có thể tạo @pytest.mark.database_accessđiểm đánh dấu cho chúng.

Mẹo chuyên nghiệp : Vì bạn có thể đặt tên cho nhãn hiệu của mình bất kỳ tên nào bạn muốn, nên có thể dễ dàng nhập nhầm hoặc ghi nhớ sai tên nhãn hiệu. pytestsẽ cảnh báo bạn về các dấu mà nó không nhận ra.

Các --strict-markerslá cờ để các pytestlệnh đảm bảo rằng tất cả các dấu ngoặc trong các thử nghiệm của bạn được đăng ký tại của bạn pytestcấu hình. Nó sẽ ngăn bạn chạy các bài kiểm tra của mình cho đến khi bạn đăng ký bất kỳ điểm nào không xác định.

Để biết thêm thông tin về việc đăng ký nhãn hiệu, hãy xem pytesttài liệu .

Khi đến thời điểm chạy các bài kiểm tra của bạn, bạn vẫn có thể chạy tất cả chúng theo mặc định bằng pytestlệnh. Nếu bạn chỉ muốn chạy những thử nghiệm yêu cầu quyền truy cập cơ sở dữ liệu, thì bạn có thể sử dụng pytest -m database_access. Để chạy tất cả các bài kiểm tra ngoại trừ những bài kiểm tra yêu cầu quyền truy cập cơ sở dữ liệu, bạn có thể sử dụng pytest -m "not database_access". Bạn thậm chí có thể sử dụng một autousevật cố định để giới hạn quyền truy cập cơ sở dữ liệu vào những bài kiểm tra được đánh dấu bằng database_access.

Một số plugin mở rộng chức năng của nhãn hiệu bằng cách bảo vệ quyền truy cập vào tài nguyên. Các pytest-djangoplugin cung cấp một django_dbdấu ấn. Bất kỳ bài kiểm tra nào không có dấu này mà cố gắng truy cập cơ sở dữ liệu sẽ không thành công. Thử nghiệm đầu tiên cố gắng truy cập cơ sở dữ liệu sẽ kích hoạt việc tạo cơ sở dữ liệu thử nghiệm của Django.

Yêu cầu bạn thêm django_dbdấu thúc đẩy bạn phải nêu rõ các yếu tố phụ thuộc của bạn. Đó là pytesttriết lý, sau tất cả! Điều đó cũng có nghĩa là bạn có thể chạy các bài kiểm tra không dựa vào cơ sở dữ liệu nhanh hơn nhiều, vì pytest -m "not django_db"sẽ ngăn kiểm tra kích hoạt việc tạo cơ sở dữ liệu. Tiết kiệm thời gian thực sự tăng lên, đặc biệt nếu bạn siêng năng chạy các bài kiểm tra của mình thường xuyên.

pytest cung cấp một vài dấu hiệu ngoài hộp:

  • skip bỏ qua bài kiểm tra một cách vô điều kiện.
  • skipifbỏ qua kiểm tra nếu biểu thức được chuyển đến nó được đánh giá là True.
  • xfailchỉ ra rằng một bài kiểm tra dự kiến ​​sẽ không thành công, vì vậy nếu bài kiểm tra không thành công, bộ tổng thể vẫn có thể dẫn đến trạng thái vượt qua.
  • parametrize(lưu ý chính tả) tạo ra nhiều biến thể của một bài kiểm tra với các giá trị khác nhau làm đối số. Bạn sẽ sớm tìm hiểu thêm về nhãn hiệu này.

Bạn có thể xem danh sách tất cả các nhãn hiệu pytestbiết về bằng cách chạy pytest --markers.

Tham số hóa: Kết hợp các bài kiểm tra

Bạn đã thấy trước đó trong hướng dẫn này cách pytestsử dụng đồ đạc để giảm sự trùng lặp mã bằng cách trích xuất các phần phụ thuộc phổ biến. Các thiết bị cố định không hoàn toàn hữu ích khi bạn có một số thử nghiệm với đầu vào và đầu ra mong đợi hơi khác nhau. Trong những trường hợp này, bạn có thể tham số hóa một định nghĩa thử nghiệm duy nhất và pytestsẽ tạo các biến thể của thử nghiệm cho bạn với các tham số bạn chỉ định.

Hãy tưởng tượng bạn đã viết một hàm để cho biết một chuỗi có phải là palindrome hay không . Một tập hợp các bài kiểm tra ban đầu có thể trông như thế này:

def test_is_palindrome_empty_string():
    assert is_palindrome("")

def test_is_palindrome_single_character():
    assert is_palindrome("a")

def test_is_palindrome_mixed_casing():
    assert is_palindrome("Bob")

def test_is_palindrome_with_spaces():
    assert is_palindrome("Never odd or even")

def test_is_palindrome_with_punctuation():
    assert is_palindrome("Do geese see God?")

def test_is_palindrome_not_palindrome():
    assert not is_palindrome("abc")

def test_is_palindrome_not_quite():
    assert not is_palindrome("abab")

Tất cả các bài kiểm tra này ngoại trừ hai bài kiểm tra cuối cùng có cùng hình dạng:

def test_is_palindrome_<in some situation>():
    assert is_palindrome("")

Bạn có thể sử dụng @pytest.mark.parametrize()để điền vào hình dạng này với các giá trị khác nhau, giảm đáng kể mã thử nghiệm của bạn:

@pytest.mark.parametrize("palindrome", [
    "",
    "a",
    "Bob",
    "Never odd or even",
    "Do geese see God?",
])
def test_is_palindrome(palindrome):
    assert is_palindrome(palindrome)

@pytest.mark.parametrize("non_palindrome", [
    "abc",
    "abab",
])
def test_is_palindrome_not_palindrome(non_palindrome):
    assert not is_palindrome(non_palindrome)

Đối số đầu tiên parametrize()là một chuỗi tên tham số được phân tách bằng dấu phẩy. Đối số thứ hai là danh sách các bộ giá trị hoặc các giá trị đơn đại diện cho (các) giá trị tham số. Bạn có thể tiến thêm một bước nữa trong quá trình tham số hóa để kết hợp tất cả các thử nghiệm của mình thành một:

@pytest.mark.parametrize("maybe_palindrome, expected_result", [
    ("", True),
    ("a", True),
    ("Bob", True),
    ("Never odd or even", True),
    ("Do geese see God?", True),
    ("abc", False),
    ("abab", False),
])
def test_is_palindrome(maybe_palindrome, expected_result):
    assert is_palindrome(maybe_palindrome) == expected_result

Mặc dù điều này đã rút ngắn mã của bạn, nhưng điều quan trọng cần lưu ý là trong trường hợp này, nó không có tác dụng gì nhiều để làm rõ mã thử nghiệm của bạn. Sử dụng tham số hóa để tách dữ liệu thử nghiệm khỏi hành vi thử nghiệm để rõ ràng thử nghiệm đang thử nghiệm những gì!

Báo cáo thời lượng: Chiến đấu với các bài kiểm tra chậm

Mỗi lần bạn chuyển đổi ngữ cảnh từ mã triển khai sang mã kiểm tra, bạn phải chịu một số chi phí . Nếu các bài kiểm tra của bạn bắt đầu chậm, thì chi phí đầu vào có thể gây ra xích mích và thất vọng.

Bạn đã đọc trước đó về cách sử dụng điểm để lọc ra các bài kiểm tra chậm khi bạn chạy bộ phần mềm của mình. Nếu bạn muốn cải thiện tốc độ của các bài kiểm tra của mình, thì sẽ hữu ích khi biết những bài kiểm tra nào có thể mang lại những cải tiến lớn nhất. pytestcó thể tự động ghi lại thời lượng kiểm tra cho bạn và báo cáo những người vi phạm hàng đầu.

Sử dụng --durationstùy chọn cho pytestlệnh để đưa báo cáo thời lượng vào kết quả kiểm tra của bạn. --durationsmong đợi một giá trị số nguyên nvà sẽ báo cáo nsố lần kiểm tra chậm nhất . Đầu ra sẽ theo kết quả kiểm tra của bạn:

$ pytest --durations=3
3.03s call     test_code.py::test_request_read_timeout
1.07s call     test_code.py::test_request_connection_timeout
0.57s call     test_code.py::test_database_read
======================== 7 passed in 10.06s ==============================

Mỗi bài kiểm tra hiển thị trong báo cáo thời lượng là một ứng cử viên tốt để tăng tốc vì nó chiếm số lượng trên mức trung bình trong tổng thời gian kiểm tra.

Lưu ý rằng một số thử nghiệm có thể có chi phí thiết lập vô hình. Bạn đã đọc trước đó về cách thử nghiệm đầu tiên được đánh dấu django_dbsẽ kích hoạt việc tạo cơ sở dữ liệu thử nghiệm Django. Các durationsbáo cáo phản ánh thời gian cần thiết để thiết lập cơ sở dữ liệu trong bài kiểm tra đó kích hoạt việc tạo ra cơ sở dữ liệu, có thể được gây hiểu lầm.

Các pytestplugin hữu ích

Bạn đã tìm hiểu về một số pytestplugin có giá trị trước đó trong hướng dẫn này. Bạn có thể khám phá những thứ đó và một vài thứ khác sâu hơn bên dưới.

pytest-randomly

pytest-randomlythực hiện một điều gì đó tưởng như đơn giản nhưng lại có hiệu quả có giá trị: Nó buộc các thử nghiệm của bạn chạy theo một thứ tự ngẫu nhiên. pytestluôn thu thập tất cả các bài kiểm tra mà nó có thể tìm thấy trước khi chạy chúng, do đó, pytest-randomlyxáo trộn danh sách các bài kiểm tra đó ngay trước khi thực hiện.

Đây là một cách tuyệt vời để khám phá các bài kiểm tra phụ thuộc vào việc chạy theo một thứ tự cụ thể, có nghĩa là chúng có sự phụ thuộc trạng thái vào một số bài kiểm tra khác. Nếu bạn đã xây dựng bộ thử nghiệm của mình từ đầu pytest, thì điều này không có khả năng xảy ra. Nó có nhiều khả năng xảy ra hơn trong các bộ thử nghiệm mà bạn di chuyển đến pytest.

Plugin sẽ in giá trị hạt giống trong mô tả cấu hình. Bạn có thể sử dụng giá trị đó để chạy các bài kiểm tra theo thứ tự khi bạn cố gắng khắc phục sự cố.

pytest-cov

Nếu bạn đo lường mức độ phù hợp của các thử nghiệm đối với mã triển khai, bạn có thể sử dụng gói bảo hiểm . pytest-covtích hợp phạm vi bảo hiểm, vì vậy bạn có thể chạy pytest --covđể xem báo cáo về phạm vi kiểm tra.

pytest-django

pytest-djangocung cấp một số đồ đạc và điểm đánh dấu hữu ích để đối phó với các bài kiểm tra Django. Bạn đã thấy django_dbdấu hiệu trước đó trong hướng dẫn này và rfvật cố định cung cấp quyền truy cập trực tiếp vào một phiên bản của Django RequestFactory. Vật settingscố định cung cấp một cách nhanh chóng để thiết lập hoặc ghi đè cài đặt Django. Đây là một sự thúc đẩy tuyệt vời cho năng suất thử nghiệm Django của bạn!

Nếu bạn quan tâm đến việc tìm hiểu thêm về cách sử dụng pytestvới Django, hãy xem Cách cung cấp thiết bị kiểm tra cho mô hình Django trong Pytest .

pytest-bdd

pytestcó thể được sử dụng để chạy các bài kiểm tra nằm ngoài phạm vi truyền thống của kiểm thử đơn vị. Phát triển theo hướng hành vi (BDD) khuyến khích viết mô tả bằng ngôn ngữ đơn giản về các hành động và mong đợi của người dùng, sau đó bạn có thể sử dụng để xác định xem có triển khai một tính năng nhất định hay không. pytest-bdd giúp bạn sử dụng Gherkin để viết các bài kiểm tra tính năng cho mã của bạn.

Bạn có thể xem các plugin khác có sẵn pytestvới danh sách mở rộng các plugin của bên thứ ba này .

Phần kết luận

pytestcung cấp một tập hợp các tính năng năng suất cốt lõi để lọc và tối ưu hóa các thử nghiệm của bạn cùng với hệ thống plugin linh hoạt giúp mở rộng giá trị của nó hơn nữa. Cho dù bạn có một bộ kế thừa khổng lồ unittesthay bạn đang bắt đầu một dự án mới từ đầu, pytestđều có thứ gì đó để cung cấp cho bạn.

Trong hướng dẫn này, bạn đã học cách sử dụng:

  • Đồ đạc để xử lý các phụ thuộc kiểm tra, trạng thái và chức năng có thể sử dụng lại
  • Dấu hiệu để phân loại các bài kiểm tra và giới hạn quyền truy cập vào các nguồn bên ngoài
  • Tham số hóa để giảm mã trùng lặp giữa các lần kiểm tra
  • Khoảng thời gian để xác định các bài kiểm tra chậm nhất của bạn
  • Các plugin để tích hợp với các khuôn khổ và công cụ kiểm tra khác

Cài đặt pytestvà dùng thử. Bạn sẽ vui vì bạn đã làm. Chúc bạn thử nghiệm vui vẻ!

Hướng dẫn dùng pytest django python

Các khóa học qua video:
Lập trình C Java SQL Server PHP HTML5-CSS3-JavaScript
« Prev: Python: Các kiểu dữ liệu cơ bản trong Python
» Next: Python: Bố cục PyQt: Tạo các ứng dụng GUI chuyên nghiệp