Tham khảo API Pytest - Các hàm chức năng

Mục lục- Các hàm chức năng (Functions)

  • pytest.approx
  • pytest.fail
  • pytest.skip
  • pytest.importorskip
  • pytest.xfail
  • pytest.exit
  • pytest.main
  • pytest.param
  • pytest.raises
  • pytest.deprecated_call
  • pytest.register_assert_rewrite
  • pytest.warns
  • pytest.freeze_includes

Quay lại: Hướng dẫn Pytest đầy đủ

Các hàm chức năng

pytest.approx

Khẳng định hai số (hoặc hai tập hợp số) bằng nhau trong một phạm vi dung sai nhất định.

Do sự phức tạp của phép toán số thực, những số mà chúng ta kỳ vọng bằng nhau về mặt lý thuyết đôi khi không thực sự như vậy:

0.3 + 0.4 == 0.7
False

Khi viết các bài kiểm tra, bạn thường gặp vấn đề này, ví dụ khi đảm bảo các giá trị dấu phẩy động có đúng như kỳ vọng. Một cách xử lý vấn đề này là khẳng định hai số dấu phẩy động bằng nhau trong một dung sai phù hợp:

 abs((0.3 + 0.4) - 0.7) < 1e-6
True

Tuy nhiên, việc so sánh như vậy vừa tẻ nhạt lại khó hiểu. Ngoài ra, cách so sánh tuyệt đối như trên không được khuyến khích vì không có dung sai phù hợp cho mọi tình huống. 1e-6 có thể phù hợp với các số xung quanh 1, nhưng đối với các số rất lớn thì quá nhỏ và đối với các số rất nhỏ thì lại quá lớn. Tốt hơn nên biểu diễn dung sai dưới dạng một phần nhỏ của giá trị kỳ vọng, nhưng việc so sánh tương đối như vậy khó viết đúng và ngắn gọn hơn.

Lớp approx sử dụng cú pháp càng trực quan càng tốt để thực hiện so sánh số thực:

 from pytest import approx
>>> 0.3 + 0.4 == approx(0.7)
True

Cú pháp tương tự cũng hoạt động với các chuỗi số:

 (0.3 + 0.4,0.5 + 0.5) == approx((0.7,1.0))
True

Các giá trị trong từ điển:

 {'x': 0.3 + 0.4,'y': 0.5 + 0.5} == approx({'x': 0.7,'y': 1.0})
True

Các mảng numpy:

 import numpy as np
>>> np.array([0.3,0.4]) + np.array([0.4,0.6]) == approx(np.array([0.7,1.0])) 
True

Đối với các mảng có giá trị vô hướng numpy:

 import numpy as np
>>> np.array([0.3,0.4]) + np.array([0.4,0.3]) == approx(0.7)
True

Theo mặc định, approx sẽ coi các số trong dung sai tương đối 1e-6 (tức là một phần triệu) của giá trị kỳ vọng là bằng nhau. Nếu giá trị kỳ vọng là 0.0, cách xử lý này sẽ cho kết quả đáng ngạc nhiên, vì ngoài 0.0 ra không có gì là 0.0. Để xử lý tình huống này một cách ít đáng ngạc nhiên hơn, approx cũng coi các số trong dung sai tuyệt đối 1e-12 của giá trị kỳ vọng là bằng nhau. Vô cực và NaN là các trường hợp đặc biệt. Dù dung sai tương thế nào, vô cực chỉ được coi là bằng với chính nó. Theo mặc định, NaN không được coi là bằng với bất cứ thứ gì, nhưng bạn có thể đặt tham số nan_ok thành True để nó bằng với chính nó. (Điều này nhằm thuận tiện cho việc so sánh các mảng sử dụng NaN để biểu thị "không có dữ liệu".)

Bằng cách chuyển các đối số cho hàm khởi tạo approx, bạn có thể thay đổi dung sai tương đối và dung sai tuyệt đối:

 1.0002 == approx(1)
False
>>> 1.0002 == approx(1,rel=1e-3)
True
>>> 1.0002 == approx(1,abs=1e-3)
True

Nếu bạn chỉ định abs mà không chỉ định rel, thì việc so sánh sẽ không xem xét dung sai tương đối. Nói cách khác, hai số trong dung sai tương đối mặc định 1e-6 vẫn sẽ được coi là không bằng nhau nếu vượt qua dung sai tuyệt đối được chỉ định. Nếu chỉ định cả absrel, nếu một trong hai dung sai được đáp ứng, số sẽ được coi là bằng nhau:

 1 + 2e-8 == approx(1)
True
>>> 1 + 2e-8 == approx(1,abs=1e-12)
False
>>> 1 + 2e-8 == approx(1,rel=1e-6,abs=1e-12)
True

pytest.fail

Tham khảo: Bỏ qua và xfail: Xử lý các bài kiểm tra không thành công

fail(msg='', pytrace=True): Thiết lập rõ ràng trạng thái thất bại cho trường hợp kiểm tra với thông điệp đã cho.

Tham số:

  • msg(str) - Thông điệp hiển thị nguyên nhân thất bại cho người dùng.
  • pytrace(bool) - Nếu là false, thì msg biểu thị thông tin thất bại hoàn chỉnh và không báo cáo bất kỳ bản traceback python nào.

pytest.skip

skip(msg[, allow_module_level=False]): Bỏ qua trường hợp kiểm tra với thông điệp đã cho.

Chỉ nên được gọi trong quá trình kiểm tra (thiết lập, gọi hoặc dọn dẹp) hoặc được gọi trong quá trình thu thập với cờ allow_module_level. Hàm này cũng có thể được gọi trong các doctest.

Tham số:

  • allow_module_level(bool) - Cho phép gọi hàm này ở cấp độ mô-đun, bỏ qua phần còn lại của mô-đun. Mặc định là False.

Lưu ý: Nên sử dụng dấu pytest.mark.skipif để tuyên bố các bài kiểm tra bị bỏ qua trong một số điều kiện, chẳng hạn như nền tảng không khớp hoặc các phần phụ thuộc không có. Tương tự, sử dụng chỉ thị #doctest: + SKIP (xem doctest.SKIP) có thể bỏ qua doctest một cách tĩnh.

pytest.importorskip

importorskip(modname, minversion=None, reason=None): Nhập và trả về mô-đun được yêu cầu modname, hoặc nếu không thể nhập mô-đun, thì bỏ qua bài kiểm tra hiện tại.

Tham số:

  • modname(str) - Tên của mô-đun cần nhập
  • minversion(str) - Nếu được đưa ra, thuộc tính __version__ của mô-đun nhập phải là phiên bản tối thiểu này, nếu không bài kiểm tra vẫn sẽ bị bỏ qua.
  • reason(str) - Nếu được đưa ra, lý do này sẽ được hiển thị dưới dạng thông điệp khi không thể nhập mô-đun.

pytest.xfail

xfail(reason=''): Buộc đánh dấu trường hợp kiểm tra hoặc hàm chuẩn bị thất bại với lý do đã cho.

Chỉ có thể sử dụng hàm này trong hàm kiểm tra, hàm thiết lập hoặc hàm dọn dẹp.

Lưu ý: Nên sử dụng dấu pytest.mark.xfail để tuyên bố bài kiểm tra có phải là xfailed trong một số điều kiện (như lỗi đã biết hoặc thiếu tính năng).

pytest.exit

exit(msg, returncode=None): Thoát khỏi quá trình kiểm tra.

Tham số:

  • msg(str) - Thông điệp được hiển thị khi thoát.
  • returncode(int) - Mã trả về được sử dụng khi thoát khỏi pytest.

pytest.main

main(args=None, plugins=None): Thực hiện trình chạy kiểm tra trong quy trình và trả về mã thoát.

Tham số:

  • args- Danh sách các đối số dòng lệnh.
  • plugins- Danh sách các đối tượng plugin được tự động đăng ký trong quá trình khởi tạo.

pytest.param

param(*values[, id][, marks]): Chỉ định tham số trong [pytest.mark.parametrize.

@pytest.mark.parametrize("input,kết_quả",[
    ("4+6",10),
    pytest.param("7*8",56,marks=pytest.mark.xfail),
])
def test_tính_toán(input,kết_quả):
    assert eval(input) == kết_quả

Tham số:

  • values- Các giá trị tập tham số theo thứ tự dưới dạng biến args.
  • dấu- Một dấu hiệu hoặc danh sách các dấu hiệu áp dụng cho tập tham số này.
  • id(str) - Thuộc về tập tham số này.

pytest.raises

Tham khảo: Khẳng định về ngoại lệ dự kiến.

with raises(expected_exception: Exception[, match][, message]) as excinfo: Khẳng định khối mã/lời gọi hàm sẽ ném ra expected_exception hoặc ném ra ngoại lệ thất bại.

Tham số:

  • match- Nếu được chỉ định, khẳng định ngoại lệ phù hợp với văn bản hoặc regex
  • message-**(Từ phiên bản 4.1 không còn dùng)**Nếu được chỉ định, cung cấp thông điệp thất bại tùy chỉnh nếu ngoại lệ không được ném ra

Sử dụng trình quản lý ngữ cảnh pytest.raises, điều này sẽ bắt một loại ngoại lệ cụ thể:

>>> with raises(ZeroDivisionError):
...    1/0

Nếu khối mã không ném ra ngoại lệ được mong đợi (ZeroDivisionError trong ví dụ trên), hoặc không có ngoại lệ nào, thì bài kiểm tra sẽ thất bại.

Bạn cũng có thể sử dụng đối số từ khóa match để khẳng định ngoại lệ phù hợp với văn bản hoặc regex:

>>> with raises(ValueError,match='phải là 0 hoặc None'):
...     raise ValueError("giá trị phải là 0 hoặc None")

>>> with raises(ValueError,match=r'phải là \d+/pre>):
...     raise ValueError("giá trị phải là 42")

Trình quản lý ngữ cảnh tạo ra một đối tượng ExceptionInfo, có thể được sử dụng để kiểm tra chi tiết của ngoại lệ bắt được:

>>> with raises(ValueError) as exc_info:
...     raise ValueError("giá trị phải là 42")
>>> assert exc_info.type is ValueError
>>> assert exc_info.value.args[0] == "giá trị phải là 42"

pytest.deprecated_call

Tham khảo: Đảm bảo mã kích hoạt cảnh báo không còn dùng.

with deprecated_call(): Trình quản lý ngữ cảnh, có thể được sử dụng để đảm bảo khối mã kích hoạt DeprecationWarning hoặc PendingDeprecationWarning:

 import warnings
>>> def api_goi_thanh_phien_ban_moi():
...     warnings.warn('sử dụng phiên bản v3 của api này',DeprecationWarning)
...     return 200

>>> with deprecated_call():
...    assert api_goi_thanh_phien_ban_moi() == 200

deprecated_call cũng có thể được sử dụng bằng cách chuyển một hàm, *args*kwargs, trong trường hợp này, nó sẽ đảm bảo lời gọi tạo ra một trong các loại cảnh báo được đề cập ở trên. func(*args,**kwargs)

pytest.register_assert_rewrite

Tham khảo: Viết lại khẳng định.

register_assert_rewrite(*names): Đăng ký một hoặc nhiều tên mô-đun cần được viết lại khi nhập.

Hàm này sẽ đảm bảo rằng tất cả các mô-đun trong mô-đun hoặc gói này sẽ viết lại các câu lệnh assert của chúng. Do đó, bạn nên đảm bảo gọi phương thức này trước khi thực sự nhập mô-đun, và nếu bạn là một plugin sử dụng gói, thì thường được gọi trong __init__.py.

Ném ra: TypeError- Nếu tên mô-đun được đưa ra không phải là chuỗi.

pytest.warns

Tham khảo: Sử dụng chức cảnh báo để phát ra cảnh báo

with warns(expected_warning: Exception[, match]): Khẳng định mã sẽ ném ra một loại cảnh báo cụ thể.

Cụ thể, tham số expected_warning có thể là một lớp cảnh báo hoặc một chuỗi lớp cảnh báo, và bên trong khối with phải phát ra cảnh báo của lớp này hoặc các lớp này.

Trợ thủ này tạo ra một danh sách các đối tượng warnings.WarningMessage, mỗi cảnh báo được ném ra tạo ra một đối tượng.

Hàm này có thể được sử dụng dưới dạng trình quản lý ngữ cảnh, tương tự như pytest.raises, hoặc theo bất kỳ cách nào khác:

 with warns(RuntimeWarning):
...    warnings.warn("cảnh báo của tôi",RuntimeWarning)

Trong hình thức trình quản lý ngữ cảnh, bạn có thể sử dụng đối số từ khóa match để khẳng định ngoại lệ phù hợp với văn bản hoặc regex:

 with warns(UserWarning,match='phải là 0 hoặc None'):
...     warnings.warn("giá trị phải là 0 hoặc None",UserWarning)

>>> with warns(UserWarning,match=r'phải là \d+/pre>):
...     warnings.warn("giá trị phải là 42",UserWarning)

>>> with warns(UserWarning,match=r'phải là \d+/pre>):
...     warnings.warn("đây không có ở đây",UserWarning)
Traceback (most recent call last):
  ...
Failed: KHÔNG CẢNH BÁO. Không có cảnh báo nào của loại ...UserWarning... được phát ra...

pytest.freeze_includes

Tham khảo: Đóng băng pytest.

freeze_includes(): Trả về danh sách tên mô-đun được pytest sử dụng, nên được cx_freeze bao gồm.

Thẻ: pytest API Functions testing

Đăng vào ngày 29 tháng 7 lúc 15:26