Thông tin cơ bản về Pytest
Hãy bắt đầu thử nghiệm với Pytest. Như chúng tôi đã đề cập trong đơn vị trước, Pytest có thể đặt cấu hình cao và có thể xử lý các bộ kiểm tra phức tạp, nhưng nó không yêu cầu nhiều để bắt đầu kiểm tra viết. Trong thực tế, một khuôn khổ dễ dàng hơn cho phép bạn viết bài kiểm tra, càng tốt.
Đến cuối phần này, bạn sẽ có mọi thứ bạn cần để bắt đầu viết bài kiểm tra đầu tiên của mình và chạy chúng với Pytest.
Quy ước
Trước khi tìm hiểu về các bài kiểm tra viết, chúng ta phải đề cập đến một số quy ước thử nghiệm mà Pytest dựa vào.
Không có nhiều quy tắc cứng về các tệp thử nghiệm, thư mục thử nghiệm hoặc bố trí kiểm tra chung trong Python. Bằng cách biết những quy tắc này, bạn có thể tận dụng khám phá và thực thi tự động kiểm tra mà không cần bất kỳ cấu hình bổ sung nào.
Kiểm tra thư mục và kiểm tra tệp
Thư mục chính cho các xét nghiệm là kiểm kiểm tra mục. Bạn có thể đặt thư mục này ở cấp gốc của dự án, nhưng cũng không có gì lạ khi nhìn thấy thư mục này cùng với các mô-đun mã.
Ghi
Trong mô-đun này, chúng tôi sẽ mặc định sử dụng các kiểm tra tại gốc của một dự án.
Hãy xem làm thế nào gốc rễ của một dự án Python nhỏ có tên là jformat hình:
.
├── README.md
├── jformat
│ ├── __init__.py
│ └── main.py
├── setup.py
└── tests
└── test_main.py
Việc kiểm thư mục là gốc của dự án với một tệp kiểm tra duy nhất. Trong trường hợp này, tệp thử nghiệm được gọi là test_main.py. Ví dụ này minh họa hai quy ước quan trọng:
- Sử dụng một kiểm tra mục để đặt các tệp thử nghiệm và các thư mục kiểm tra lồng nhau.
- Kiểm tra tiền tố tệp với thử. Tiền tố cho biết tệp chứa mã kiểm tra.
Thận trọng
Tránh sử test (biểu mẫu đơn) làm tên thư mục. Tên test là một mô-đun Python, vì vậy việc tạo một thư mục có tên giống nhau sẽ ghi đè nó. Luôn luôn sử dụng số tests để thay thế.
Hàm kiểm tra
Một đối số mạnh mẽ để sử dụng Pytest là nó cho phép bạn viết các hàm kiểm tra. Tương tự như các tệp kiểm tra, các hàm kiểm tra phải được đặt tiền tố test_. Tiền tố test_ đảm bảo rằng Pytest thu thập kiểm tra và thực thi nó.
Đây là diện mạo của một hàm kiểm tra đơn giản:
def test_main():
assert "a string value" == "a string value"
Ghi
Nếu bạn đã quen thuộc với unittest, bạn có thể ngạc nhiên khi thấy việc sử dụng assert hàm kiểm tra. Sau này, chúng tôi sẽ đề cập chi tiết hơn về các xác nhận đơn giản, nhưng với Pytest, bạn sẽ nhận được báo cáo lỗi phong phú với các xác nhận đơn giản.
Các lớp kiểm tra và phương pháp kiểm tra
Tương tự như các quy ước cho các tập tin và chức năng, lớp thử nghiệm và phương pháp thử nghiệm sử dụng các quy ước sau đây:
- Các lớp kiểm tra có tiền tố là
Test - Các phương pháp kiểm tra có tiền tố là
test_
Sự khác biệt cốt lõi với thư viện unittest của Python là không cần thừa kế.
Ví dụ sau đây sử dụng các tiền tố này và các quy ước đặt tên Python khác cho các lớp và phương pháp. Nó chứng minh một lớp học thử nghiệm nhỏ đó là kiểm tra tên người dùng trong một ứng dụng.
class TestUser:
def test_username(self):
assert default() == "default username"
Chạy kiểm tra
Pytest vừa là một chương trình thử nghiệm và là một người chạy thử. Runner thử nghiệm là một thực thi trong dòng lệnh (ở mức cao) có thể:
- Thực hiện thu thập các kiểm tra bằng cách tìm tất cả các tệp thử nghiệm, các lớp kiểm tra và các hàm kiểm tra cho một lần chạy thử.
- Khởi tạo chạy thử nghiệm bằng cách thực hiện tất cả các kiểm tra.
- Theo dõi lỗi, lỗi và vượt qua kiểm tra.
- Cung cấp báo cáo phong phú khi kết thúc chạy thử.
Ghi
Vì Pytest là một thư viện bên ngoài, nó phải được cài đặt để sử dụng nó.
Với những nội dung này trong một test_main.py, chúng ta có thể thấy cách Pytest hoạt động chạy các bài kiểm tra:
# contents of test_main.py file
def test_main():
assert True
Trong dòng lệnh, trong cùng một đường dẫn nơi tồn tại tệp test_main.py, chúng ta có thể chạy tệp pytest thực thi:
$ pytest
=========================== test session starts ============================
platform -- Python 3.10.1, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
rootdir: /private/tmp/project
collected 1 item
test_main.py . [100%]
============================ 1 passed in 0.00s =============================
Ở hậu trường, Pytest sẽ thu thập bài kiểm tra ví dụ trong tệp thử nghiệm mà không cần bất kỳ cấu hình nào.
Câu lệnh càng mạnh mẽ
Cho đến nay, các ví dụ thử nghiệm của chúng tôi đều sử dụng cuộc gọi assert thuần. Thông thường, trong Python, assert câu lệnh không được sử dụng để kiểm tra, vì câu lệnh thiếu báo cáo thích hợp khi không hiển thị được. Tuy nhiên, Pytest không có giới hạn này. Ở hậu trường, Pytest cho phép câu lệnh thực hiện các so sánh phong phú mà không buộc người dùng viết thêm mã hoặc đặt cấu hình bất cứ điều gì.
Bằng cách sử dụng câu assert lệnh thuần, bạn có thể sử dụng toán tử của Python; ví dụ: >, <, !=, >=, hoặc <=. Tất cả các toán tử của Python đều hợp lệ. Khả năng này có thể là tính năng quan trọng nhất duy nhất của Pytest: bạn không cần phải tìm hiểu cú pháp mới để viết xác nhận.
Hãy xem làm thế nào mà dịch khi đối phó với so sánh phổ biến với các đối tượng Python. Trong trường hợp này, chúng ta hãy xem qua báo cáo lỗi khi so sánh các chuỗi dài:
================================= FAILURES =================================
____________________________ test_long_strings _____________________________
def test_long_strings():
left = "this is a very long strings to be compared with another long string"
right = "This is a very long string to be compared with another long string"
> assert left == right
E AssertionError: assert 'this is a ve...r long string' == 'This is a ve...r long string'
E - This is a very long string to be compared with another long string
E ? ^
E + this is a very long strings to be compared with another long string
E ? ^ +
test_main.py:4: AssertionError
Pytest hiển thị ngữ cảnh hữu ích xung quanh lỗi: kiểu vỏ không chính xác ở đầu chuỗi và một ký tự bổ sung trong một từ. Ngoài các chuỗi, Pytest có thể trợ giúp với các đối tượng và cấu trúc dữ liệu khác. Ví dụ, đây là cách nó hoạt động với các danh sách:
________________________________ test_lists ________________________________
def test_lists():
left = ["sugar", "wheat", "coffee", "salt", "water", "milk"]
right = ["sugar", "coffee", "wheat", "salt", "water", "milk"]
> assert left == right
E AssertionError: assert ['sugar', 'wh...ater', 'milk'] == ['sugar', 'co...ater', 'milk']
E At index 1 diff: 'wheat' != 'coffee'
E Full diff:
E - ['sugar', 'coffee', 'wheat', 'salt', 'water', 'milk']
E ? ---------
E + ['sugar', 'wheat', 'coffee', 'salt', 'water', 'milk']
E ? +++++++++
test_main.py:9: AssertionError
Báo cáo này xác định chỉ mục 1 (mục thứ hai trong danh sách) khác nhau. Nó không chỉ xác định số chỉ mục, nó còn cung cấp một đại diện của sự thất bại. Ngoài việc so sánh mục, nó cũng có thể báo cáo nếu mục bị thiếu và cung cấp thông tin có thể cho bạn biết chính xác mục có thể là mục nào. Trong trường hợp sau đây được "milk":
________________________________ test_lists ________________________________
def test_lists():
left = ["sugar", "wheat", "coffee", "salt", "water", "milk"]
right = ["sugar", "wheat", "salt", "water", "milk"]
> assert left == right
E AssertionError: assert ['sugar', 'wh...ater', 'milk'] == ['sugar', 'wh...ater', 'milk']
E At index 2 diff: 'coffee' != 'salt'
E Left contains one more item: 'milk'
E Full diff:
E - ['sugar', 'wheat', 'salt', 'water', 'milk']
E + ['sugar', 'wheat', 'coffee', 'salt', 'water', 'milk']
E ? ++++++++++
test_main.py:9: AssertionError
Cuối cùng, chúng ta hãy xem nó hoạt động như thế nào với các từ điển. So sánh hai từ điển lớn có thể là quá nhiều nếu có thất bại, nhưng Pytest thực hiện một công việc xuất sắc trong việc cung cấp ngữ cảnh và xác định sự thất bại:
____________________________ test_dictionaries _____________________________
def test_dictionaries():
left = {"street": "Ferry Ln.", "number": 39, "state": "Nevada", "zipcode": 30877, "county": "Frett"}
right = {"street": "Ferry Lane", "number": 38, "state": "Nevada", "zipcode": 30877, "county": "Frett"}
> assert left == right
E AssertionError: assert {'county': 'F...rry Ln.', ...} == {'county': 'F...ry Lane', ...}
E Omitting 3 identical items, use -vv to show
E Differing items:
E {'street': 'Ferry Ln.'} != {'street': 'Ferry Lane'}
E {'number': 39} != {'number': 38}
E Full diff:
E {
E 'county': 'Frett',...
E
E ...Full output truncated (12 lines hidden), use '-vv' to show
Trong kiểm tra này, có hai lỗi trong từ điển. Một là giá trị "street" khác nhau và giá trị khác là giá "number" không khớp.
Pytest phát hiện chính xác những khác biệt này (mặc dù đó là một lỗi trong một kiểm tra duy nhất). Vì từ điển chứa nhiều mục nên Pytest sẽ bỏ qua các phần giống nhau và chỉ hiển thị nội dung liên quan. Hãy xem điều gì sẽ xảy ra nếu chúng ta sử dụng cờ -vv đề xuất để tăng mức độ chi tiết trong đầu ra:
____________________________ test_dictionaries _____________________________
def test_dictionaries():
left = {"street": "Ferry Ln.", "number": 39, "state": "Nevada", "zipcode": 30877, "county": "Frett"}
right = {"street": "Ferry Lane", "number": 38, "state": "Nevada", "zipcode": 30877, "county": "Frett"}
> assert left == right
E AssertionError: assert {'county': 'Frett',\n 'number': 39,\n 'state': 'Nevada',\n 'street': 'Ferry Ln.',\n 'zipcode': 30877} == {'county': 'Frett',\n 'number': 38,\n 'state': 'Nevada',\n 'street': 'Ferry Lane',\n 'zipcode': 30877}
E Common items:
E {'county': 'Frett', 'state': 'Nevada', 'zipcode': 30877}
E Differing items:
E {'number': 39} != {'number': 38}
E {'street': 'Ferry Ln.'} != {'street': 'Ferry Lane'}
E Full diff:
E {
E 'county': 'Frett',
E - 'number': 38,
E ? ^
E + 'number': 39,
E ? ^
E 'state': 'Nevada',
E - 'street': 'Ferry Lane',
E ? - ^
E + 'street': 'Ferry Ln.',
E ? ^
E 'zipcode': 30877,
E }
Bằng cách chạy pytest -vv, báo cáo sẽ tăng số lượng chi tiết và cung cấp so sánh chi tiết. Báo cáo này không chỉ phát hiện và hiển thị lỗi mà còn cho phép bạn nhanh chóng thực hiện thay đổi để khắc phục sự cố.