doctest --- Kiểm tra các ví dụ Python tương tác¶
Source code: Lib/doctest.py
Mô-đun doctest tìm kiếm các đoạn văn bản trông giống như các phiên Python tương tác, sau đó thực thi các phiên đó để xác minh rằng chúng hoạt động chính xác như được hiển thị. Có một số cách phổ biến để sử dụng doctest:
Để kiểm tra xem chuỗi tài liệu của mô-đun có được cập nhật hay không bằng cách xác minh rằng tất cả các ví dụ tương tác vẫn hoạt động như tài liệu.
Để thực hiện kiểm tra hồi quy bằng cách xác minh rằng các ví dụ tương tác từ tệp kiểm tra hoặc đối tượng kiểm tra hoạt động như mong đợi.
Để viết tài liệu hướng dẫn cho một gói, được minh họa một cách phóng khoáng bằng các ví dụ đầu vào-đầu ra. Tùy thuộc vào việc các ví dụ hoặc văn bản giải thích có được nhấn mạnh hay không, điều này có tính chất "kiểm tra khả năng đọc viết" hoặc "tài liệu có thể thực thi".
Đây là một mô-đun ví dụ hoàn chỉnh nhưng nhỏ:
"""
Đây là mô-đun "ví dụ".
Mô-đun ví dụ cung cấp một hàm, giai thừa(). Ví dụ,
>>> giai thừa(5)
120
"""
giai thừa def (n):
"""Trả về giai thừa của n, một số nguyên chính xác >= 0.
>>> [giai thừa(n) cho n trong phạm vi(6)]
[1, 1, 2, 6, 24, 120]
>>> giai thừa(30)
265252859812191058636308480000000
>>> giai thừa(-1)
Traceback (cuộc gọi gần đây nhất):
...
Giá trịLỗi: n phải >= 0
Giai thừa của số float là được, nhưng số float phải là số nguyên chính xác:
>>> giai thừa(30.1)
Traceback (cuộc gọi gần đây nhất):
...
ValueError: n phải là số nguyên chính xác
>>> giai thừa(30.0)
265252859812191058636308480000000
Nó cũng không được lớn một cách lố bịch:
>>> giai thừa(1e100)
Traceback (cuộc gọi gần đây nhất):
...
TrànLỗi: n quá lớn
"""
nhập toán
nếu không n >= 0:
tăng ValueError("n phải >= 0")
nếu math.floor(n) != n:
raise ValueError("n phải là số nguyên chính xác")
nếu n+1 == n: # catch một giá trị như 1e300
tăng OverflowError ("n quá lớn")
kết quả = 1
hệ số = 2
trong khi hệ số <= n:
kết quả *= hệ số
hệ số += 1
kết quả trả về
nếu __name__ == "__main__":
nhập doctest
doctest.testmod()
Nếu bạn chạy example.py trực tiếp từ dòng lệnh, doctest sẽ hoạt động kỳ diệu:
$ python example.py
$
Không có đầu ra! Điều đó là bình thường và có nghĩa là tất cả các ví dụ đều hoạt động. Chuyển -v vào tập lệnh và doctest in nhật ký chi tiết về những gì nó đang cố gắng và in bản tóm tắt ở cuối:
$ python example.py -v
Đang cố gắng:
giai thừa(5)
Đang mong đợi:
120
được
Đang cố gắng:
[giai thừa(n) cho n trong phạm vi(6)]
Đang mong đợi:
[1, 1, 2, 6, 24, 120]
được
Và cứ thế, cuối cùng kết thúc bằng:
Đang cố gắng:
giai thừa(1e100)
Đang mong đợi:
Traceback (cuộc gọi gần đây nhất):
...
TrànLỗi: n quá lớn
được
2 mục đã vượt qua tất cả các bài kiểm tra:
1 bài kiểm tra trong __main__
6 bài kiểm tra trong __main__.factorial
7 bài kiểm tra trong 2 mục.
7 đã trôi qua.
Thử nghiệm đã trôi qua.
$
Đó là tất cả những gì bạn cần biết để bắt đầu sử dụng doctest một cách hiệu quả! Hãy tham gia. Các phần sau đây cung cấp đầy đủ thông tin chi tiết. Lưu ý rằng có nhiều ví dụ về doctest trong bộ thư viện và bộ thử nghiệm Python tiêu chuẩn. Các ví dụ đặc biệt hữu ích có thể được tìm thấy trong tệp thử nghiệm tiêu chuẩn Lib/test/test_doctest/test_doctest.py.
Added in version 3.13: Đầu ra được tô màu theo mặc định và có thể là controlled using environment variables.
Cách sử dụng đơn giản: Kiểm tra các ví dụ trong Docstrings¶
Cách đơn giản nhất để bắt đầu sử dụng doctest (nhưng không nhất thiết phải theo cách bạn sẽ tiếp tục làm) là kết thúc mỗi mô-đun M bằng:
nếu __name__ == "__main__":
nhập doctest
doctest.testmod()
doctest sau đó kiểm tra các chuỗi tài liệu trong mô-đun M.
Việc chạy mô-đun dưới dạng tập lệnh sẽ khiến các ví dụ trong chuỗi tài liệu được thực thi và xác minh:
trăn M.py
Điều này sẽ không hiển thị bất cứ điều gì trừ khi một ví dụ bị lỗi, trong trường hợp đó (các) ví dụ bị lỗi và (các) nguyên nhân của (các) lỗi được in ra thiết bị xuất chuẩn và dòng đầu ra cuối cùng là ***Test Failed*** N failures., trong đó N là số lượng các ví dụ bị lỗi.
Thay vào đó hãy chạy nó bằng công tắc -v
trăn M.py -v
và một báo cáo chi tiết về tất cả các ví dụ đã thử sẽ được in ra đầu ra tiêu chuẩn, cùng với các loại tóm tắt ở cuối.
Bạn có thể buộc chế độ dài dòng bằng cách chuyển verbose=True sang testmod() hoặc cấm chế độ này bằng cách chuyển verbose=False. Trong cả hai trường hợp đó, sys.argv không được testmod() kiểm tra (vì vậy việc vượt qua -v hay không đều không có hiệu lực).
Ngoài ra còn có một phím tắt dòng lệnh để chạy testmod(), xem phần Sử dụng dòng lệnh.
Để biết thêm thông tin về testmod(), hãy xem phần API cơ bản.
Cách sử dụng đơn giản: Kiểm tra các ví dụ trong tệp văn bản¶
Một ứng dụng đơn giản khác của doctest là kiểm tra các ví dụ tương tác trong một tệp văn bản. Điều này có thể được thực hiện với chức năng testfile():
nhập doctest
doctest.testfile("example.txt")
Tập lệnh ngắn đó thực thi và xác minh mọi ví dụ Python tương tác có trong tệp example.txt. Nội dung tệp được xử lý như thể nó là một chuỗi tài liệu khổng lồ; tệp không cần chứa chương trình Python! Ví dụ: có lẽ example.txt chứa cái này:
Mô-đun ``example``
========================
Sử dụng ``factorial``
-------------------
Đây là một tệp văn bản mẫu ở định dạng reStructuredText. Lần nhập đầu tiên
``factorial`` từ mô-đun ``example``:
>>> từ ví dụ nhập giai thừa
Bây giờ sử dụng nó:
>>> giai thừa(6)
120
Chạy doctest.testfile("example.txt") thì thấy lỗi trong tài liệu này
Tệp "./example.txt", dòng 14, trong example.txt
Ví dụ không thành công:
giai thừa(6)
Dự kiến:
120
Có:
720
Như với testmod(), testfile() sẽ không hiển thị bất cứ thứ gì trừ khi một ví dụ bị lỗi. Nếu một ví dụ không thành công thì (các) ví dụ bị lỗi và (các) nguyên nhân của (các) lỗi đó sẽ được in ra thiết bị xuất chuẩn, sử dụng cùng định dạng như testmod().
Theo mặc định, testfile() tìm kiếm các tập tin trong thư mục của mô-đun gọi điện. Xem phần API cơ bản để biết mô tả về các đối số tùy chọn có thể được sử dụng để yêu cầu nó tìm kiếm tệp ở các vị trí khác.
Giống như testmod(), mức độ chi tiết của testfile() có thể được đặt bằng khóa chuyển dòng lệnh -v hoặc bằng đối số từ khóa tùy chọn verbose.
Ngoài ra còn có một phím tắt dòng lệnh để chạy testfile(), xem phần Sử dụng dòng lệnh.
Để biết thêm thông tin về testfile(), hãy xem phần API cơ bản.
Sử dụng dòng lệnh¶
Mô-đun doctest có thể được gọi dưới dạng tập lệnh từ dòng lệnh:
python -m doctest [-v] [-o OPTION] [-f] tệp [tệp ...]
- -v, --verbose¶
Báo cáo chi tiết của tất cả các ví dụ đã thử được in ra đầu ra tiêu chuẩn, cùng với các loại tóm tắt ở cuối:
python -m doctest -v example.py
Điều này sẽ nhập
example.pydưới dạng mô-đun độc lập và chạytestmod()trên đó. Lưu ý rằng điều này có thể không hoạt động chính xác nếu tệp là một phần của gói và nhập các mô-đun con khác từ gói đó.Nếu tên tệp không kết thúc bằng
.py, thìdoctestsẽ suy ra rằng nó phải được chạy bằngtestfile():python -m doctest -v example.txt
- -o, --option <option>¶
Cờ tùy chọn kiểm soát các khía cạnh khác nhau trong hành vi của doctest, xem phần Cờ tùy chọn.
Added in version 3.4.
- -f, --fail-fast¶
Đây là cách viết tắt của
-o FAIL_FAST.Added in version 3.4.
Nó hoạt động như thế nào¶
Phần này xem xét chi tiết cách thức hoạt động của doctest: nó xem xét chuỗi tài liệu nào, cách nó tìm thấy các ví dụ tương tác, bối cảnh thực thi mà nó sử dụng, cách nó xử lý các ngoại lệ và cách các cờ tùy chọn có thể được sử dụng để kiểm soát hành vi của nó. Đây là thông tin bạn cần biết để viết những ví dụ hay nhất; để biết thông tin về việc thực sự chạy doctest trên các ví dụ này, hãy xem các phần sau.
Những tài liệu nào được kiểm tra?¶
Chuỗi tài liệu mô-đun và tất cả các chuỗi tài liệu hàm, lớp và phương thức đều được tìm kiếm. Các đối tượng được nhập vào mô-đun không được tìm kiếm.
Ngoài ra, có những trường hợp bạn muốn các bài kiểm tra là một phần của mô-đun nhưng không phải là một phần của văn bản trợ giúp, điều này yêu cầu các bài kiểm tra không được đưa vào chuỗi tài liệu. Doctest tìm kiếm một biến cấp mô-đun có tên là __test__ và sử dụng nó để xác định các thử nghiệm khác. Nếu M.__test__ tồn tại, nó phải là một lệnh chính tả và mỗi mục nhập ánh xạ một tên (chuỗi) tới một đối tượng hàm, đối tượng lớp hoặc chuỗi. Các chuỗi tài liệu đối tượng hàm và lớp được tìm thấy từ M.__test__ sẽ được tìm kiếm và các chuỗi được xử lý như thể chúng là các chuỗi tài liệu. Trong đầu ra, khóa K trong M.__test__ xuất hiện với tên M.__test__.K.
Ví dụ: đặt khối mã này ở đầu example.py:
__kiểm tra__ = {
'số': """
>>> giai thừa(6)
720
>>> [giai thừa(n) cho n trong phạm vi(6)]
[1, 1, 2, 6, 24, 120]
"""
}
Giá trị của example.__test__["numbers"] sẽ được coi là một chuỗi tài liệu và tất cả các thử nghiệm bên trong nó sẽ được chạy. Điều quan trọng cần lưu ý là giá trị có thể được ánh xạ tới một hàm, đối tượng lớp hoặc mô-đun; nếu vậy, doctest sẽ tìm kiếm các chuỗi tài liệu một cách đệ quy, sau đó sẽ được quét để kiểm tra.
Bất kỳ lớp nào được tìm thấy đều được tìm kiếm đệ quy theo cách tương tự, để kiểm tra các chuỗi tài liệu trong các phương thức được chứa và các lớp lồng nhau của chúng.
Ghi chú
doctest chỉ có thể tự động khám phá các lớp và hàm được xác định ở cấp mô-đun hoặc bên trong các lớp khác.
Vì các lớp và hàm lồng nhau chỉ tồn tại khi hàm bên ngoài được gọi nên chúng không thể được phát hiện. Xác định chúng bên ngoài để làm cho chúng hiển thị.
Các ví dụ về chuỗi tài liệu được công nhận như thế nào?¶
Trong hầu hết các trường hợp, việc sao chép và dán phiên bảng điều khiển tương tác đều hoạt động tốt, nhưng doctest không cố gắng thực hiện mô phỏng chính xác bất kỳ trình bao Python cụ thể nào.
>>> # comments bị bỏ qua
>>> x = 12
>>>x
12
>>> nếu x == 13:
... in("có")
... khác:
... in("không")
... in("KHÔNG")
... in("KHÔNG!!!")
...
không
KHÔNG
KHÔNG!!!
>>>
Mọi đầu ra dự kiến phải ngay sau dòng '>>> ' hoặc '... ' cuối cùng chứa mã và đầu ra dự kiến (nếu có) sẽ mở rộng đến dòng '>>> ' hoặc toàn khoảng trắng tiếp theo.
Bản in đẹp:
Đầu ra dự kiến không thể chứa một dòng toàn khoảng trắng, vì dòng như vậy được dùng để báo hiệu sự kết thúc của đầu ra dự kiến. Nếu đầu ra dự kiến chứa một dòng trống, hãy đặt
<BLANKLINE>vào ví dụ tài liệu tốt nhất của bạn mỗi nơi dự kiến sẽ có một dòng trống.Tất cả các ký tự tab cứng đều được mở rộng thành khoảng trắng, sử dụng các điểm dừng tab 8 cột. Các tab trong đầu ra do mã kiểm tra tạo ra không được sửa đổi. Bởi vì bất kỳ tab cứng nào trong đầu ra mẫu are đều được mở rộng, điều này có nghĩa là nếu đầu ra mã bao gồm các tab cứng, cách duy nhất doctest có thể vượt qua là nếu tùy chọn
NORMALIZE_WHITESPACEhoặc directive có hiệu lực. Ngoài ra, bài kiểm tra có thể được viết lại để nắm bắt kết quả đầu ra và so sánh nó với giá trị mong đợi như một phần của bài kiểm tra. Việc xử lý các tab trong nguồn này được thực hiện thông qua quá trình thử và sai và đã được chứng minh là cách xử lý chúng ít xảy ra lỗi nhất. Có thể sử dụng một thuật toán khác để xử lý các tab bằng cách viết một lớpDocTestParsertùy chỉnh.Đầu ra cho thiết bị xuất chuẩn được ghi lại, nhưng không xuất ra thiết bị xuất chuẩn (các dấu vết ngoại lệ được ghi lại thông qua một phương tiện khác).
Nếu bạn tiếp tục một dòng thông qua dấu gạch chéo ngược trong phiên tương tác hoặc vì bất kỳ lý do nào khác mà sử dụng dấu gạch chéo ngược, bạn nên sử dụng chuỗi tài liệu thô, chuỗi này sẽ giữ nguyên dấu gạch chéo ngược chính xác khi bạn nhập chúng:
>>> định nghĩa f(x): ... r'''Dấu gạch chéo ngược trong chuỗi tài liệu thô: m\n''' ... >>> in(f.__doc__) Dấu gạch chéo ngược trong chuỗi tài liệu thô: m\n
Nếu không, dấu gạch chéo ngược sẽ được hiểu là một phần của chuỗi. Ví dụ:
\nở trên sẽ được hiểu là ký tự dòng mới. Ngoài ra, bạn có thể nhân đôi mỗi dấu gạch chéo ngược trong phiên bản doctest (và không sử dụng chuỗi thô):>>> định nghĩa f(x): ... '''Dấu gạch chéo ngược trong chuỗi tài liệu thô: m\\n''' ... >>> in(f.__doc__) Dấu gạch chéo ngược trong chuỗi tài liệu thô: m\n
Cột bắt đầu không quan trọng:
>>> khẳng định "Dễ dàng!" >>> nhập toán >>> math.floor(1.9) 1
và nhiều ký tự khoảng trắng ở đầu bị loại bỏ khỏi kết quả mong đợi như đã xuất hiện trong dòng
'>>> 'ban đầu bắt đầu ví dụ.
Bối cảnh thực thi là gì?¶
Theo mặc định, mỗi lần doctest tìm thấy một chuỗi tài liệu để kiểm tra, nó sẽ sử dụng một chuỗi tài liệu shallow copy trong số các toàn cục của M để việc chạy thử nghiệm không làm thay đổi các chuỗi toàn cục thực của mô-đun và do đó một thử nghiệm trong M không thể để lại các mẩu vụn vô tình cho phép một thử nghiệm khác hoạt động. Điều này có nghĩa là các ví dụ có thể tự do sử dụng bất kỳ tên nào được xác định ở cấp cao nhất trong M và các tên được xác định trước đó trong chuỗi tài liệu đang được chạy. Ví dụ không thể thấy tên được xác định trong các chuỗi tài liệu khác.
Thay vào đó, bạn có thể buộc sử dụng lệnh của riêng mình làm bối cảnh thực thi bằng cách chuyển globs=your_dict sang testmod() hoặc testfile().
Điều gì về ngoại lệ?¶
Không vấn đề gì, miễn là truy nguyên là đầu ra duy nhất được tạo ra bởi ví dụ: chỉ cần dán vào truy nguyên. [1] Vì các dấu vết chứa các chi tiết có khả năng thay đổi nhanh chóng (ví dụ: đường dẫn tệp và số dòng chính xác), đây là một trường hợp mà doctest cố gắng hết sức để linh hoạt trong những gì nó chấp nhận.
Ví dụ đơn giản:
>>> [1, 2, 3].remove(42)
Traceback (cuộc gọi gần đây nhất):
Tệp "<stdin>", dòng 1, trong <module>
ValueError: list.remove(x): x không có trong danh sách
Doctest đó thành công nếu ValueError được nâng lên, với chi tiết list.remove(x): x not in list như được hiển thị.
Đầu ra dự kiến cho một ngoại lệ phải bắt đầu bằng tiêu đề truy nguyên, có thể là một trong hai dòng sau, được thụt lề giống như dòng đầu tiên của ví dụ:
Traceback (cuộc gọi gần đây nhất):
Traceback (trong cùng cuối cùng):
Tiêu đề truy nguyên được theo sau bởi một ngăn xếp truy nguyên tùy chọn, nội dung của nó bị doctest bỏ qua. Ngăn xếp truy nguyên thường bị bỏ qua hoặc được sao chép nguyên văn từ một phiên tương tác.
Tiếp theo ngăn xếp truy nguyên là phần thú vị nhất: (các) dòng chứa loại ngoại lệ và chi tiết. Đây thường là dòng cuối cùng của truy nguyên, nhưng có thể mở rộng trên nhiều dòng nếu ngoại lệ có chi tiết nhiều dòng:
>>> tăng ValueError('multi\n line\ndetail')
Traceback (cuộc gọi gần đây nhất):
Tệp "<stdin>", dòng 1, trong <module>
Giá trịLỗi: đa
dòng
chi tiết
Ba dòng cuối cùng (bắt đầu bằng ValueError) được so sánh với loại và chi tiết của ngoại lệ, phần còn lại bị bỏ qua.
Cách thực hành tốt nhất là bỏ qua ngăn xếp truy nguyên, trừ khi nó bổ sung thêm giá trị tài liệu quan trọng vào ví dụ. Vì vậy, ví dụ cuối cùng có lẽ tốt hơn là:
>>> tăng ValueError('multi\n line\ndetail')
Traceback (cuộc gọi gần đây nhất):
...
Giá trịLỗi: đa
dòng
chi tiết
Lưu ý rằng việc truy nguyên được xử lý rất đặc biệt. Đặc biệt, trong ví dụ viết lại, việc sử dụng ... độc lập với tùy chọn ELLIPSIS của doctest. Dấu chấm lửng trong ví dụ đó có thể bị bỏ đi hoặc cũng có thể là ba (hoặc ba trăm) dấu phẩy hoặc chữ số hoặc bản ghi thụt lề của một tiểu phẩm Monty Python.
Một số chi tiết bạn nên đọc một lần nhưng sẽ không cần phải nhớ:
Doctest không thể đoán liệu kết quả mong đợi của bạn đến từ việc truy nguyên ngoại lệ hay từ quá trình in thông thường. Vì vậy, ví dụ: một ví dụ mong đợi
ValueError: 42 is primesẽ vượt qua dùValueErrorcó thực sự được nâng lên hay nếu ví dụ đó chỉ in văn bản truy nguyên đó. Trong thực tế, đầu ra thông thường hiếm khi bắt đầu bằng dòng tiêu đề truy ngược, do đó điều này không tạo ra vấn đề thực sự.Mỗi dòng của ngăn xếp truy ngược (nếu có) phải được thụt lề xa hơn dòng đầu tiên của ví dụ, or bắt đầu bằng ký tự không phải chữ và số. Dòng đầu tiên sau tiêu đề truy nguyên được thụt lề giống nhau và bắt đầu bằng chữ và số được coi là phần bắt đầu của chi tiết ngoại lệ. Tất nhiên điều này là đúng đối với các hoạt động truy nguyên chính hãng.
Khi tùy chọn doctest
IGNORE_EXCEPTION_DETAILđược chỉ định, mọi thứ sau dấu hai chấm ngoài cùng bên trái và mọi thông tin mô-đun trong tên ngoại lệ đều bị bỏ qua.Shell tương tác bỏ qua dòng tiêu đề truy nguyên đối với một số
SyntaxErrors. Nhưng doctest sử dụng dòng tiêu đề truy nguyên để phân biệt các trường hợp ngoại lệ với không phải ngoại lệ. Vì vậy, trong trường hợp hiếm hoi khi bạn cần kiểm tra mộtSyntaxErrorbỏ qua tiêu đề traceback, bạn sẽ cần thêm dòng tiêu đề traceback vào ví dụ kiểm tra của mình theo cách thủ công.
Đối với một số trường hợp ngoại lệ, Python hiển thị vị trí lỗi bằng cách sử dụng dấu
^và dấu ngã:>>> 1 + Không Tệp "<stdin>", dòng 1 1 + Không ~~^~~~~~~ TypeError: (các) loại toán hạng không được hỗ trợ cho +: 'int' và 'NoneType'
Vì các dòng hiển thị vị trí lỗi xuất hiện trước loại và chi tiết ngoại lệ nên chúng không được doctest kiểm tra. Ví dụ: bài kiểm tra sau sẽ đạt, mặc dù nó đặt điểm đánh dấu
^ở sai vị trí:>>> 1 + Không Tệp "<stdin>", dòng 1 1 + Không ^~~~~~~~~ TypeError: (các) loại toán hạng không được hỗ trợ cho +: 'int' và 'NoneType'
Cờ tùy chọn¶
Một số cờ tùy chọn kiểm soát các khía cạnh khác nhau trong hành vi của doctest. Tên tượng trưng cho các cờ được cung cấp dưới dạng hằng số mô-đun, có thể là bitwise ORed cùng nhau và được chuyển đến các hàm khác nhau. Tên cũng có thể được sử dụng trong doctest directives và có thể được chuyển đến giao diện dòng lệnh doctest thông qua tùy chọn -o.
Nhóm tùy chọn đầu tiên xác định ngữ nghĩa kiểm tra, kiểm soát các khía cạnh về cách doctest quyết định xem đầu ra thực tế có khớp với đầu ra dự kiến của một ví dụ hay không:
- doctest.DONT_ACCEPT_TRUE_FOR_1¶
Theo mặc định, nếu khối đầu ra dự kiến chỉ chứa
1thì khối đầu ra thực tế chỉ chứa1hoặc chỉTrueđược coi là phù hợp và tương tự đối với0so vớiFalse. KhiDONT_ACCEPT_TRUE_FOR_1được chỉ định, không được phép thay thế. Hành vi mặc định phục vụ cho việc Python đã thay đổi kiểu trả về của nhiều hàm từ số nguyên sang boolean; doctests mong đợi đầu ra "số nguyên nhỏ" vẫn hoạt động trong những trường hợp này. Tùy chọn này có thể sẽ biến mất, nhưng không phải trong vài năm nữa.
- doctest.DONT_ACCEPT_BLANKLINE¶
Theo mặc định, nếu khối đầu ra dự kiến chứa một dòng chỉ chứa chuỗi
<BLANKLINE>thì dòng đó sẽ khớp với một dòng trống trong đầu ra thực tế. Bởi vì một dòng trống thực sự sẽ phân định kết quả đầu ra dự kiến, đây là cách duy nhất để thông báo rằng một dòng trống được mong đợi. KhiDONT_ACCEPT_BLANKLINEđược chỉ định, sự thay thế này không được phép.
- doctest.NORMALIZE_WHITESPACE¶
Khi được chỉ định, tất cả các chuỗi khoảng trắng (khoảng trống và dòng mới) đều được coi là bằng nhau. Bất kỳ chuỗi khoảng trắng nào trong kết quả đầu ra dự kiến sẽ khớp với bất kỳ chuỗi khoảng trắng nào trong kết quả đầu ra thực tế. Theo mặc định, khoảng trắng phải khớp chính xác.
NORMALIZE_WHITESPACEđặc biệt hữu ích khi một dòng đầu ra dự kiến rất dài và bạn muốn gói nó thành nhiều dòng trong nguồn của mình.
- doctest.ELLIPSIS¶
Khi được chỉ định, dấu chấm lửng (
...) trong đầu ra dự kiến có thể khớp với bất kỳ chuỗi con nào trong đầu ra thực tế. Điều này bao gồm các chuỗi con mở rộng ranh giới dòng và các chuỗi con trống, vì vậy tốt nhất bạn nên sử dụng chuỗi này một cách đơn giản. Việc sử dụng phức tạp có thể dẫn đến cùng một kiểu "ôi, nó khớp quá nhiều!" những điều ngạc nhiên mà.*thường gặp phải trong các biểu thức thông thường.
- doctest.IGNORE_EXCEPTION_DETAIL¶
Khi được chỉ định, các doctest mong đợi ngoại lệ sẽ vượt qua miễn là ngoại lệ của loại dự kiến được nêu ra, ngay cả khi các chi tiết (thông báo và tên ngoại lệ đủ điều kiện) không khớp.
Ví dụ: một ví dụ mong đợi
ValueError: 42sẽ vượt qua nếu ngoại lệ thực tế được đưa ra làValueError: 3*14, nhưng sẽ thất bại nếu thay vào đó, mộtTypeErrorđược đưa ra. Nó cũng sẽ bỏ qua mọi tên đủ điều kiện được đưa vào trước lớp ngoại lệ, tên này có thể khác nhau giữa các cách triển khai và phiên bản Python cũng như mã/thư viện đang sử dụng. Do đó, cả ba biến thể này sẽ hoạt động với cờ được chỉ định:>>> tăng Ngoại lệ ('tin nhắn') Traceback (cuộc gọi gần đây nhất): Ngoại lệ: tin nhắn >>> tăng Ngoại lệ ('tin nhắn') Traceback (cuộc gọi gần đây nhất): nội dung.Exception: tin nhắn >>> tăng Ngoại lệ ('tin nhắn') Traceback (cuộc gọi gần đây nhất): __main__.Ngoại lệ: tin nhắn
Lưu ý rằng
ELLIPSIScũng có thể được sử dụng để bỏ qua các chi tiết của thông báo ngoại lệ, nhưng việc kiểm tra như vậy vẫn có thể thất bại dựa trên việc tên mô-đun có xuất hiện hay khớp chính xác hay không.Thay đổi trong phiên bản 3.2:
IGNORE_EXCEPTION_DETAILhiện cũng bỏ qua mọi thông tin liên quan đến mô-đun chứa ngoại lệ đang được thử nghiệm.
- doctest.SKIP¶
Khi được chỉ định, không chạy ví dụ nào cả. Điều này có thể hữu ích trong các bối cảnh trong đó các ví dụ doctest đóng vai trò vừa là tài liệu vừa là trường hợp kiểm thử, đồng thời nên đưa vào một ví dụ cho mục đích ghi lại tài liệu nhưng không nên kiểm tra. Ví dụ: đầu ra của ví dụ có thể là ngẫu nhiên; hoặc ví dụ có thể phụ thuộc vào các tài nguyên không có sẵn cho trình điều khiển thử nghiệm.
Cờ SKIP cũng có thể được sử dụng cho các ví dụ "bình luận" tạm thời.
- doctest.COMPARISON_FLAGS¶
Một bitmask hoặc kết hợp tất cả các cờ so sánh ở trên.
Nhóm tùy chọn thứ hai kiểm soát cách báo cáo lỗi kiểm tra:
- doctest.REPORT_UDIFF¶
Khi được chỉ định, các lỗi liên quan đến đầu ra thực tế và dự kiến nhiều dòng sẽ được hiển thị bằng cách sử dụng khác biệt thống nhất.
- doctest.REPORT_CDIFF¶
Khi được chỉ định, các lỗi liên quan đến đầu ra thực tế và dự kiến nhiều dòng sẽ được hiển thị bằng cách sử dụng ngữ cảnh khác nhau.
- doctest.REPORT_NDIFF¶
Khi được chỉ định, sự khác biệt sẽ được
difflib.Differtính toán, sử dụng thuật toán tương tự như tiện íchndiff.pyphổ biến. Đây là phương pháp duy nhất đánh dấu sự khác biệt giữa các dòng cũng như giữa các dòng. Ví dụ: nếu một dòng đầu ra dự kiến chứa chữ số1trong đó đầu ra thực tế chứa chữ cáil, thì một dòng sẽ được chèn bằng dấu mũ đánh dấu các vị trí cột không khớp.
- doctest.REPORT_ONLY_FIRST_FAILURE¶
Khi được chỉ định, hãy hiển thị ví dụ bị lỗi đầu tiên trong mỗi doctest, nhưng chặn đầu ra đối với tất cả các ví dụ còn lại. Điều này sẽ ngăn doctest báo cáo các ví dụ chính xác bị hỏng do lỗi trước đó; nhưng nó cũng có thể che giấu các ví dụ không chính xác bị lỗi độc lập với lỗi đầu tiên. Khi
REPORT_ONLY_FIRST_FAILUREđược chỉ định, các mẫu còn lại vẫn chạy và vẫn được tính vào tổng số lỗi được báo cáo; chỉ có đầu ra bị triệt tiêu.
- doctest.FAIL_FAST¶
Khi được chỉ định, hãy thoát sau ví dụ lỗi đầu tiên và không cố chạy các ví dụ còn lại. Do đó, số lỗi được báo cáo sẽ nhiều nhất là 1. Cờ này có thể hữu ích trong quá trình gỡ lỗi, vì các ví dụ sau lỗi đầu tiên thậm chí sẽ không tạo ra kết quả gỡ lỗi.
- doctest.REPORTING_FLAGS¶
Một bitmask hoặc kết hợp tất cả các cờ báo cáo ở trên.
Ngoài ra còn có một cách để đăng ký tên cờ tùy chọn mới, mặc dù điều này không hữu ích trừ khi bạn có ý định mở rộng nội bộ doctest thông qua phân lớp:
- doctest.register_optionflag(name)¶
Tạo cờ tùy chọn mới với tên đã cho và trả về giá trị số nguyên của cờ mới.
register_optionflag()có thể được sử dụng khi phân lớpOutputCheckerhoặcDocTestRunnerđể tạo các tùy chọn mới được các lớp con của bạn hỗ trợ.register_optionflag()phải luôn được gọi bằng cách sử dụng thành ngữ sauMY_FLAG = register_optionflag('MY_FLAG')
Chỉ thị¶
Các chỉ thị Doctest có thể được sử dụng để sửa đổi option flags cho một ví dụ riêng lẻ. Các lệnh Doctest là các nhận xét Python đặc biệt theo mã nguồn của một ví dụ:
directive: "#" "doctest:"directive_optionsdirective_options:directive_option(","directive_option)* directive_option:on_or_offdirective_option_nameon_or_off: "+" | "-" directive_option_name: "DONT_ACCEPT_BLANKLINE" | "NORMALIZE_WHITESPACE" | ...
Không được phép có khoảng trắng giữa + hoặc - và tên tùy chọn chỉ thị. Tên tùy chọn chỉ thị có thể là bất kỳ tên cờ tùy chọn nào được giải thích ở trên.
Các chỉ thị doctest của một ví dụ sửa đổi hành vi của doctest cho ví dụ đó. Sử dụng + để kích hoạt hành vi được đặt tên hoặc - để tắt nó.
Ví dụ: bài kiểm tra này đạt:
>>> print(list(range(20))) # doctest: +NORMALIZE_WHITESPACE
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
Nếu không có lệnh này thì nó sẽ thất bại, cả vì đầu ra thực tế không có hai khoảng trống trước các phần tử danh sách một chữ số và vì đầu ra thực tế nằm trên một dòng. Bài kiểm tra này cũng vượt qua và cũng yêu cầu chỉ thị để thực hiện:
>>> print(list(range(20))) # doctest: +ELLIPSIS
[0, 1, ..., 18, 19]
Nhiều lệnh có thể được sử dụng trên một dòng vật lý, được phân tách bằng dấu phẩy:
>>> print(list(range(20))) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
[0, 1, ..., 18, 19]
Nếu nhiều nhận xét chỉ thị được sử dụng cho một ví dụ thì chúng sẽ được kết hợp:
>>> print(list(range(20))) # doctest: +ELLIPSIS
... # doctest: +NORMALIZE_WHITESPACE
[0, 1, ..., 18, 19]
Như ví dụ trước cho thấy, bạn có thể thêm các dòng ... vào ví dụ chỉ chứa các lệnh. Điều này có thể hữu ích khi một ví dụ quá dài để một lệnh có thể vừa vặn trên cùng một dòng:
>>> print(list(range(5)) + list(range(10, 20)) + list(range(30, 40)))
... # doctest: +ELLIPSIS
[0, ..., 4, 10, ..., 19, 30, ..., 39]
Lưu ý rằng vì tất cả các tùy chọn đều bị tắt theo mặc định và các lệnh chỉ áp dụng cho ví dụ mà chúng xuất hiện, nên việc bật các tùy chọn (thông qua + trong một lệnh) thường là lựa chọn có ý nghĩa duy nhất. Tuy nhiên, cờ tùy chọn cũng có thể được chuyển đến các hàm chạy doctest, thiết lập các giá trị mặc định khác nhau. Trong những trường hợp như vậy, việc tắt tùy chọn qua - trong một lệnh có thể hữu ích.
Cảnh báo¶
doctest rất nghiêm túc trong việc yêu cầu kết quả đầu ra phải khớp chính xác. Nếu thậm chí một ký tự không khớp, thử nghiệm sẽ thất bại. Điều này có thể sẽ làm bạn ngạc nhiên đôi khi vì bạn tìm hiểu chính xác những gì Python làm và không đảm bảo về đầu ra. Ví dụ: khi in một tập hợp, Python không đảm bảo rằng phần tử đó được in theo bất kỳ thứ tự cụ thể nào, do đó, hãy thử nghiệm như
>>> foo()
{"thư rác", "trứng"}
dễ bị tổn thương! Một cách giải quyết khác là làm
>>> foo() == {"spam", "trứng"}
đúng
thay vào đó. Một cách khác là làm
>>> d = đã sắp xếp(foo())
>>> d
['trứng', 'thư rác']
Có những người khác, nhưng bạn có được ý tưởng.
Một ý tưởng tồi khác là in những thứ nhúng địa chỉ đối tượng, như
>>> id(1.0) # certain đôi khi bị lỗi
7948648
>>> lớp C: đậu
>>> C() # the Repr mặc định() cho các trường hợp nhúng địa chỉ
<Đối tượng C tại 0x00AC18F0>
Lệnh ELLIPSIS đưa ra một cách tiếp cận hay cho ví dụ cuối cùng:
>>> C() # doctest: +ELLIPSIS
<Đối tượng C ở 0x...>
Các số có dấu phẩy động cũng có thể có sự thay đổi đầu ra nhỏ trên các nền tảng, vì Python sử dụng thư viện nền tảng C để thực hiện một số phép tính dấu phẩy động và các thư viện C ở đây có chất lượng rất khác nhau.
>>> 1000**0,1 # risky
1.9952623149688797
>>> vòng(1000**0.1, 9) # safer
1.995262315
>>> print(f'{1000**0.1:.4f}') # much an toàn hơn
1.9953
Các số có dạng I/2.**J an toàn trên tất cả các nền tảng và tôi thường tạo ra các ví dụ tốt nhất để tạo ra các số có dạng đó:
>>> 3./4 # utterly an toàn
0,75
Các phân số đơn giản cũng dễ hiểu hơn đối với mọi người và điều đó tạo nên tài liệu tốt hơn.
API cơ bản¶
Các hàm testmod() và testfile() cung cấp một giao diện đơn giản cho doctest, đủ cho hầu hết các mục đích sử dụng cơ bản. Để có phần giới thiệu ít trang trọng hơn về hai hàm này, hãy xem phần Cách sử dụng đơn giản: Kiểm tra các ví dụ trong Docstrings và Cách sử dụng đơn giản: Kiểm tra các ví dụ trong tệp văn bản.
- doctest.testfile(filename, module_relative=True, name=None, package=None, globs=None, verbose=None, report=True, optionflags=0, extraglobs=None, raise_on_error=False, parser=DocTestParser(), encoding=None)¶
Tất cả các đối số ngoại trừ filename đều là tùy chọn và phải được chỉ định ở dạng từ khóa.
Ví dụ thử nghiệm trong tệp có tên filename. Trả về
(failure_count, test_count).Đối số tùy chọn module_relative chỉ định cách diễn giải tên tệp:
Nếu module_relative là
True(mặc định), thì filename chỉ định đường dẫn tương đối mô-đun độc lập với hệ điều hành. Theo mặc định, đường dẫn này liên quan đến thư mục của mô-đun gọi điện; nhưng nếu đối số package được chỉ định thì nó có liên quan đến gói đó. Để đảm bảo tính độc lập của hệ điều hành, filename nên sử dụng các ký tự/để phân tách các đoạn đường dẫn và có thể không phải là đường dẫn tuyệt đối (tức là nó không được bắt đầu bằng/).Nếu module_relative là
Falsethì filename chỉ định đường dẫn dành riêng cho hệ điều hành. Đường dẫn có thể tuyệt đối hoặc tương đối; đường dẫn tương đối được giải quyết đối với thư mục làm việc hiện tại.
Đối số tùy chọn name đưa ra tên của bài kiểm tra; theo mặc định hoặc nếu
None,os.path.basename(filename)được sử dụng.Đối số tùy chọn package là gói Python hoặc tên của gói Python có thư mục nên được sử dụng làm thư mục cơ sở cho tên tệp liên quan đến mô-đun. Nếu không có gói nào được chỉ định thì thư mục của mô-đun gọi sẽ được sử dụng làm thư mục cơ sở cho tên tệp liên quan đến mô-đun. Sẽ có lỗi khi chỉ định package nếu module_relative là
False.Đối số tùy chọn globs đưa ra một lệnh được sử dụng làm toàn cục khi thực thi các ví dụ. Một bản sao nông mới của lệnh này được tạo cho doctest, vì vậy các ví dụ của nó bắt đầu bằng một bản rõ ràng. Theo mặc định hoặc nếu
None, một lệnh trống mới sẽ được sử dụng.Đối số tùy chọn extraglobs đưa ra một lệnh được hợp nhất vào các phần tổng thể được sử dụng để thực thi các ví dụ. Điều này hoạt động giống như
dict.update(): nếu globs và extraglobs có một khóa chung, giá trị liên quan trong extraglobs sẽ xuất hiện trong lệnh kết hợp. Theo mặc định hoặc nếuNone, không có tổng thể bổ sung nào được sử dụng. Đây là một tính năng nâng cao cho phép tham số hóa các doctest. Ví dụ: một doctest có thể được viết cho một lớp cơ sở, sử dụng tên chung cho lớp đó, sau đó được sử dụng lại để kiểm tra bất kỳ số lượng lớp con nào bằng cách chuyển một lệnh extraglobs ánh xạ tên chung cho lớp con cần kiểm tra.Đối số tùy chọn verbose in nhiều nội dung nếu đúng và chỉ in lỗi nếu sai; theo mặc định hoặc nếu
None, điều đó đúng khi và chỉ khi'-v'nằm trongsys.argv.Đối số tùy chọn report in bản tóm tắt ở cuối khi đúng, nếu không thì không in gì ở cuối. Ở chế độ dài dòng, bản tóm tắt rất chi tiết, nếu không thì bản tóm tắt rất ngắn gọn (trên thực tế, sẽ trống nếu tất cả các bài kiểm tra đều vượt qua).
Đối số tùy chọn optionflags (giá trị mặc định
0) lấy bitwise OR của các cờ tùy chọn. Xem phần Cờ tùy chọn.Đối số tùy chọn raise_on_error mặc định là sai. Nếu đúng, một ngoại lệ sẽ được đưa ra khi xảy ra lỗi đầu tiên hoặc ngoại lệ không mong muốn trong một ví dụ. Điều này cho phép các lỗi được gỡ lỗi sau khi chết. Hành vi mặc định là tiếp tục chạy các ví dụ.
Đối số tùy chọn parser chỉ định một
DocTestParser(hoặc lớp con) sẽ được sử dụng để trích xuất các bài kiểm tra từ các tệp. Nó mặc định là một trình phân tích cú pháp bình thường (tức làDocTestParser()).Đối số tùy chọn encoding chỉ định mã hóa sẽ được sử dụng để chuyển đổi tệp sang unicode.
- doctest.testmod(m=None, name=None, globs=None, verbose=None, report=True, optionflags=0, extraglobs=None, raise_on_error=False, exclude_empty=False)¶
Tất cả các đối số đều là tùy chọn và tất cả ngoại trừ m phải được chỉ định ở dạng từ khóa.
Ví dụ kiểm tra trong chuỗi tài liệu trong các hàm và lớp có thể truy cập được từ mô-đun m (hoặc mô-đun
__main__nếu m không được cung cấp hoặc làNone), bắt đầu bằngm.__doc__.Đồng thời kiểm tra các ví dụ có thể truy cập được từ dict
m.__test__, nếu nó tồn tại.m.__test__ánh xạ tên (chuỗi) thành các hàm, lớp và chuỗi; các chuỗi tài liệu về hàm và lớp được tìm kiếm để lấy ví dụ; các chuỗi được tìm kiếm trực tiếp, như thể chúng là các chuỗi tài liệu.Chỉ các chuỗi tài liệu gắn liền với các đối tượng thuộc mô-đun m mới được tìm kiếm.
Trả về
(failure_count, test_count).Đối số tùy chọn name cung cấp tên của mô-đun; theo mặc định hoặc nếu
None,m.__name__được sử dụng.Đối số tùy chọn exclude_empty mặc định là sai. Nếu đúng, các đối tượng không tìm thấy doctest sẽ bị loại khỏi việc xem xét. Mặc định là hack tương thích ngược, do đó mã vẫn sử dụng
doctest.master.summarizekết hợp vớitestmod()tiếp tục nhận đầu ra cho các đối tượng không có kiểm tra. Đối số exclude_empty cho hàm tạoDocTestFindermới hơn được mặc định là true.Các đối số tùy chọn extraglobs, verbose, report, optionflags, raise_on_error và globs giống như đối với hàm
testfile()ở trên, ngoại trừ việc globs mặc định làm.__dict__.
- doctest.run_docstring_examples(f, globs, verbose=False, name='NoName', compileflags=None, optionflags=0)¶
Các ví dụ thử nghiệm liên quan đến đối tượng f; ví dụ: f có thể là một chuỗi, một mô-đun, một hàm hoặc một đối tượng lớp.
Một bản sao nông của đối số từ điển globs được sử dụng cho ngữ cảnh thực thi.
Đối số tùy chọn name được sử dụng trong các thông báo lỗi và mặc định là
"NoName".Nếu đối số tùy chọn verbose là đúng, đầu ra sẽ được tạo ngay cả khi không có lỗi nào. Theo mặc định, đầu ra chỉ được tạo trong trường hợp mẫu bị lỗi.
Đối số tùy chọn compileflags cung cấp tập hợp các cờ sẽ được trình biên dịch Python sử dụng khi chạy các ví dụ. Theo mặc định, hoặc nếu
None, các cờ được suy ra tương ứng với tập hợp các tính năng trong tương lai được tìm thấy trong globs.Đối số tùy chọn optionflags hoạt động như đối với hàm
testfile()ở trên.
API đơn giản nhất¶
Khi bộ sưu tập các mô-đun doctest của bạn tăng lên, bạn sẽ muốn có một cách để chạy tất cả các doctest của chúng một cách có hệ thống. doctest cung cấp hai chức năng có thể được sử dụng để tạo bộ thử nghiệm unittest từ các mô-đun và tệp văn bản chứa doctest. Để tích hợp với khám phá thử nghiệm unittest, hãy bao gồm chức năng load_tests trong mô-đun thử nghiệm của bạn:
nhập khẩu đơn vị nhất
nhập doctest
nhập my_module_with_doctests
def Load_tests(loader, kiểm tra, bỏ qua):
test.addTests(doctest.DocTestSuite(my_module_with_doctests))
trả lại bài kiểm tra
Có hai chức năng chính để tạo phiên bản unittest.TestSuite từ tệp văn bản và mô-đun bằng doctest:
- doctest.DocFileSuite(*paths, module_relative=True, package=None, setUp=None, tearDown=None, globs=None, optionflags=0, parser=DocTestParser(), encoding=None)¶
Chuyển đổi các bài kiểm tra doctest từ một hoặc nhiều tệp văn bản sang
unittest.TestSuite.Zz000zz được trả về sẽ được chạy bởi khung nhỏ nhất và chạy các ví dụ tương tác trong mỗi tệp. Nếu một ví dụ trong bất kỳ tệp nào không thành công thì thử nghiệm đơn vị tổng hợp sẽ không thành công và ngoại lệ
failureExceptionsẽ xuất hiện hiển thị tên của tệp chứa thử nghiệm và số dòng (đôi khi gần đúng). Nếu tất cả các ví dụ trong một tệp bị bỏ qua thì bài kiểm tra đơn vị tổng hợp cũng được đánh dấu là bị bỏ qua.Truyền một hoặc nhiều đường dẫn (dưới dạng chuỗi) tới tệp văn bản cần kiểm tra.
Các tùy chọn có thể được cung cấp dưới dạng đối số từ khóa:
Đối số tùy chọn module_relative chỉ định cách diễn giải tên tệp trong paths:
Nếu module_relative là
True(mặc định), thì mỗi tên tệp trong paths chỉ định một đường dẫn tương đối mô-đun độc lập với hệ điều hành. Theo mặc định, đường dẫn này liên quan đến thư mục của mô-đun gọi điện; nhưng nếu đối số package được chỉ định thì nó có liên quan đến gói đó. Để đảm bảo tính độc lập với hệ điều hành, mỗi tên tệp phải sử dụng các ký tự/để phân tách các đoạn đường dẫn và không được là đường dẫn tuyệt đối (tức là tên tệp không được bắt đầu bằng/).Nếu module_relative là
Falsethì mỗi tên tệp trong paths chỉ định một đường dẫn dành riêng cho hệ điều hành. Đường dẫn có thể tuyệt đối hoặc tương đối; đường dẫn tương đối được giải quyết đối với thư mục làm việc hiện tại.
Đối số tùy chọn package là gói Python hoặc tên của gói Python có thư mục nên được sử dụng làm thư mục cơ sở cho tên tệp liên quan đến mô-đun trong paths. Nếu không có gói nào được chỉ định thì thư mục của mô-đun gọi sẽ được sử dụng làm thư mục cơ sở cho tên tệp liên quan đến mô-đun. Sẽ có lỗi khi chỉ định package nếu module_relative là
False.Đối số tùy chọn setUp chỉ định chức năng thiết lập cho bộ thử nghiệm. Điều này được gọi trước khi chạy thử nghiệm trong mỗi tệp. Hàm setUp sẽ được truyền vào đối tượng
DocTest. Hàm setUp có thể truy cập vào tổng thể thử nghiệm khi thuộc tínhglobscủa thử nghiệm đã vượt qua.Đối số tùy chọn tearDown chỉ định chức năng phân tích cho bộ thử nghiệm. Điều này được gọi sau khi chạy thử nghiệm trong mỗi tệp. Hàm tearDown sẽ được truyền vào đối tượng
DocTest. Hàm tearDown có thể truy cập vào tổng thể thử nghiệm khi thuộc tínhglobscủa thử nghiệm đã vượt qua.Đối số tùy chọn globs là một từ điển chứa các biến toàn cục ban đầu cho các bài kiểm tra. Một bản sao mới của từ điển này được tạo cho mỗi bài kiểm tra. Theo mặc định, globs là một từ điển trống mới.
Đối số tùy chọn optionflags chỉ định các tùy chọn doctest mặc định cho các bài kiểm tra, được tạo bằng cách kết hợp các cờ tùy chọn riêng lẻ với nhau. Xem phần Cờ tùy chọn. Xem chức năng
set_unittest_reportflags()bên dưới để biết cách đặt tùy chọn báo cáo tốt hơn.Đối số tùy chọn parser chỉ định một
DocTestParser(hoặc lớp con) sẽ được sử dụng để trích xuất các bài kiểm tra từ các tệp. Nó mặc định là một trình phân tích cú pháp bình thường (tức làDocTestParser()).Đối số tùy chọn encoding chỉ định mã hóa sẽ được sử dụng để chuyển đổi tệp sang unicode.
__file__toàn cục được thêm vào các tổng thể được cung cấp cho các tài liệu được tải từ tệp văn bản bằngDocFileSuite().
- doctest.DocTestSuite(module=None, globs=None, extraglobs=None, test_finder=None, setUp=None, tearDown=None, optionflags=0, checker=None)¶
Chuyển đổi các bài kiểm tra doctest cho một mô-đun thành
unittest.TestSuite.Zz000zz được trả về sẽ được chạy bởi khung nhỏ nhất và chạy từng doctest trong mô-đun. Mỗi chuỗi tài liệu được chạy dưới dạng thử nghiệm đơn vị riêng biệt. Nếu bất kỳ tài liệu nào không thành công thì bài kiểm tra đơn vị tổng hợp sẽ không thành công và một ngoại lệ
unittest.TestCase.failureExceptionsẽ xuất hiện hiển thị tên của tệp chứa bài kiểm tra và số dòng (đôi khi gần đúng). Nếu tất cả các ví dụ trong chuỗi tài liệu bị bỏ qua thìĐối số tùy chọn module cung cấp mô-đun cần kiểm tra. Nó có thể là một đối tượng mô-đun hoặc tên mô-đun (có thể có dấu chấm). Nếu không được chỉ định, mô-đun gọi hàm này sẽ được sử dụng.
Đối số tùy chọn globs là một từ điển chứa các biến toàn cục ban đầu cho các bài kiểm tra. Một bản sao mới của từ điển này được tạo cho mỗi bài kiểm tra. Theo mặc định, globs là
__dict__của mô-đun.Đối số tùy chọn extraglobs chỉ định một tập hợp các biến toàn cục bổ sung, được hợp nhất thành globs. Theo mặc định, không có hình cầu bổ sung nào được sử dụng.
Đối số tùy chọn test_finder là đối tượng
DocTestFinder(hoặc một đối tượng thay thế thả vào) được sử dụng để trích xuất các tài liệu từ mô-đun.Các đối số tùy chọn setUp, tearDown và optionflags giống như đối với hàm
DocFileSuite()ở trên, nhưng chúng được gọi cho mỗi chuỗi tài liệu.Chức năng này sử dụng kỹ thuật tìm kiếm tương tự như
testmod().Thay đổi trong phiên bản 3.5:
DocTestSuite()trả về mộtunittest.TestSuitetrống nếu module không chứa chuỗi tài liệu thay vì tăngValueError.
Dưới vỏ bọc, DocTestSuite() tạo ra một unittest.TestSuite từ các phiên bản doctest.DocTestCase và DocTestCase là một lớp con của unittest.TestCase. DocTestCase không được ghi lại ở đây (đây là chi tiết nội bộ), nhưng việc nghiên cứu mã của nó có thể trả lời các câu hỏi về chi tiết chính xác của việc tích hợp unittest.
Tương tự, DocFileSuite() tạo ra một unittest.TestSuite từ các phiên bản doctest.DocFileCase và DocFileCase là một lớp con của DocTestCase.
Vì vậy, cả hai cách tạo unittest.TestSuite đều chạy phiên bản DocTestCase. Điều này quan trọng vì một lý do tế nhị: khi bạn tự chạy các hàm doctest, bạn có thể kiểm soát trực tiếp các tùy chọn doctest đang được sử dụng bằng cách chuyển cờ tùy chọn cho các hàm doctest. Tuy nhiên, nếu bạn đang viết khung unittest, unittest sẽ kiểm soát thời điểm và cách thức chạy thử nghiệm. Tác giả khung thường muốn kiểm soát các tùy chọn báo cáo doctest (có thể, ví dụ: được chỉ định bởi các tùy chọn dòng lệnh), nhưng không có cách nào để chuyển các tùy chọn thông qua unittest sang các trình chạy thử nghiệm doctest.
Vì lý do này, doctest cũng hỗ trợ khái niệm cờ báo cáo doctest dành riêng cho hỗ trợ unittest, thông qua chức năng này:
- doctest.set_unittest_reportflags(flags)¶
Đặt cờ báo cáo
doctestđể sử dụng.Đối số flags lấy bitwise OR của các cờ tùy chọn. Xem phần Cờ tùy chọn. Chỉ có thể sử dụng "cờ báo cáo".
Đây là cài đặt toàn mô-đun và ảnh hưởng đến tất cả các tài liệu trong tương lai do mô-đun
unittestchạy: phương thứcrunTest()củaDocTestCasexem xét các cờ tùy chọn được chỉ định cho trường hợp thử nghiệm khi phiên bảnDocTestCaseđược tạo. Nếu không có cờ báo cáo nào được chỉ định (đó là trường hợp điển hình và được mong đợi), các cờ báo cáounittestcủadoctestsẽ được bitwise ORed đưa vào các cờ tùy chọn và các cờ tùy chọn được tăng cường như vậy sẽ được chuyển đến phiên bảnDocTestRunnerđược tạo để chạy doctest. Nếu bất kỳ cờ báo cáo nào được chỉ định khi phiên bảnDocTestCaseđược tạo, thì cờ báo cáounittestcủadoctestsẽ bị bỏ qua.Giá trị của cờ báo cáo
unittestcó hiệu lực trước khi hàm được gọi sẽ được hàm trả về.
API nâng cao¶
Zz000zz cơ bản là một trình bao bọc đơn giản nhằm mục đích giúp doctest dễ sử dụng. Nó khá linh hoạt và đáp ứng hầu hết nhu cầu của người dùng; tuy nhiên, nếu bạn yêu cầu kiểm soát chi tiết hơn đối với việc kiểm tra hoặc muốn mở rộng khả năng của doctest thì bạn nên sử dụng API nâng cao.
Zz000zz nâng cao xoay quanh hai lớp vùng chứa, được sử dụng để lưu trữ các ví dụ tương tác được trích xuất từ các trường hợp doctest:
Example: Một statement Python duy nhất, được ghép nối với đầu ra dự kiến của nó.DocTest: Một tập hợp cácExamples, thường được trích xuất từ một chuỗi tài liệu hoặc tệp văn bản.
Các lớp xử lý bổ sung được xác định để tìm, phân tích cú pháp và chạy cũng như kiểm tra các ví dụ tốt nhất:
DocTestFinder: Tìm tất cả các chuỗi tài liệu trong một mô-đun nhất định và sử dụngDocTestParserđể tạoDocTesttừ mọi chuỗi tài liệu có chứa các ví dụ tương tác.DocTestParser: Tạo đối tượngDocTesttừ một chuỗi (chẳng hạn như chuỗi tài liệu của đối tượng).DocTestRunner: Thực thi các ví dụ trongDocTestvà sử dụngOutputCheckerđể xác minh đầu ra của chúng.OutputChecker: So sánh kết quả thực tế từ một ví dụ doctest với kết quả dự kiến và quyết định xem chúng có khớp hay không.
Mối quan hệ giữa các lớp xử lý này được tóm tắt trong sơ đồ sau:
danh sách:
+------+ +----------+
|module| --DocTestFinder-> | DocTest | --DocTestRunner-> kết quả
+------+ | ^ +---------+ | ^ (đã in)
| | | Example | | |
v | | ... | v |
Trình kiểm tra đầu ra DocTestParser | Example |
+----------+
Đối tượng DocTest¶
- class doctest.DocTest(examples, globs, name, filename, lineno, docstring)¶
Một tập hợp các ví dụ tốt nhất nên được chạy trong một không gian tên duy nhất. Các đối số của hàm tạo được sử dụng để khởi tạo các thuộc tính có cùng tên.
DocTestxác định các thuộc tính sau. Chúng được khởi tạo bởi hàm tạo và không được sửa đổi trực tiếp.- examples¶
Danh sách các đối tượng
Examplemã hóa các ví dụ Python tương tác riêng lẻ sẽ được chạy trong thử nghiệm này.
- globs¶
Không gian tên (còn gọi là toàn cầu) mà các ví dụ sẽ được chạy trong đó. Đây là từ điển ánh xạ tên tới các giá trị. Mọi thay đổi đối với không gian tên do các ví dụ thực hiện (chẳng hạn như liên kết các biến mới) sẽ được phản ánh trong
globssau khi chạy thử nghiệm.
- name¶
Tên chuỗi xác định
DocTest. Thông thường, đây là tên của đối tượng hoặc tệp mà thử nghiệm được trích xuất từ đó.
- filename¶
Tên của tệp mà
DocTestnày được trích xuất từ đó; hoặcNonenếu không xác định được tên tệp hoặc nếuDocTestkhông được trích xuất từ tệp.
- lineno¶
Số dòng trong
filenamenơiDocTestnày bắt đầu hoặcNonenếu không có số dòng. Số dòng này dựa trên số 0 so với phần đầu của tệp.
- docstring¶
Chuỗi mà bài kiểm tra được trích xuất từ đó hoặc
Nonenếu chuỗi đó không có sẵn hoặc nếu bài kiểm tra không được trích xuất từ một chuỗi.
Đối tượng mẫu¶
- class doctest.Example(source, want, exc_msg=None, lineno=0, indent=0, options=None)¶
Một ví dụ tương tác duy nhất, bao gồm một câu lệnh Python và kết quả mong đợi của nó. Các đối số của hàm tạo được sử dụng để khởi tạo các thuộc tính có cùng tên.
Examplexác định các thuộc tính sau. Chúng được khởi tạo bởi hàm tạo và không được sửa đổi trực tiếp.- source¶
Một chuỗi chứa mã nguồn của ví dụ. Mã nguồn này bao gồm một câu lệnh Python duy nhất và luôn kết thúc bằng một dòng mới; hàm tạo thêm một dòng mới khi cần thiết.
- want¶
Kết quả mong đợi từ việc chạy mã nguồn của ví dụ (từ thiết bị xuất chuẩn hoặc truy nguyên trong trường hợp ngoại lệ).
wantkết thúc bằng một dòng mới trừ khi không có đầu ra nào được mong đợi, trong trường hợp đó đó là một chuỗi trống. Hàm tạo thêm một dòng mới khi cần thiết.
- exc_msg¶
Thông báo ngoại lệ do ví dụ tạo ra, nếu ví dụ đó dự kiến sẽ tạo ra ngoại lệ; hoặc
Nonenếu dự kiến nó không tạo ra ngoại lệ. Thông báo ngoại lệ này được so sánh với giá trị trả về củatraceback.format_exception_only().exc_msgkết thúc bằng một dòng mới trừ khi đó làNone. Hàm tạo thêm một dòng mới nếu cần.
- lineno¶
Số dòng trong chuỗi chứa ví dụ này nơi ví dụ bắt đầu. Số dòng này dựa trên số 0 so với phần đầu của chuỗi chứa.
- indent¶
Thụt lề của ví dụ trong chuỗi chứa, tức là số ký tự khoảng trắng đứng trước dấu nhắc đầu tiên của ví dụ.
- options¶
Ánh xạ từ điển từ cờ tùy chọn sang
TruehoặcFalse, được sử dụng để ghi đè các tùy chọn mặc định cho ví dụ này. Bất kỳ cờ tùy chọn nào không có trong từ điển này đều được giữ ở giá trị mặc định (như được chỉ định bởi optionflags củaDocTestRunner). Theo mặc định, không có tùy chọn nào được đặt.
Đối tượng DocTestFinder¶
- class doctest.DocTestFinder(verbose=False, parser=DocTestParser(), recurse=True, exclude_empty=True)¶
Một lớp xử lý được sử dụng để trích xuất các
DocTests có liên quan đến một đối tượng nhất định, từ chuỗi tài liệu của nó và các chuỗi tài liệu của các đối tượng được chứa trong đó.DocTests có thể được trích xuất từ các mô-đun, lớp, hàm, phương thức, phương thức tĩnh, phương thức lớp và thuộc tính.Đối số tùy chọn verbose có thể được sử dụng để hiển thị các đối tượng được tìm kiếm bởi công cụ tìm kiếm. Nó mặc định là
False(không có đầu ra).Đối số tùy chọn parser chỉ định đối tượng
DocTestParser(hoặc một đối tượng thay thế thả vào) được sử dụng để trích xuất các tài liệu từ chuỗi tài liệu.Nếu đối số tùy chọn recurse là sai thì
DocTestFinder.find()sẽ chỉ kiểm tra đối tượng đã cho chứ không kiểm tra bất kỳ đối tượng nào được chứa.Nếu đối số tùy chọn exclude_empty là sai thì
DocTestFinder.find()sẽ bao gồm các kiểm tra đối với các đối tượng có chuỗi tài liệu trống.DocTestFinderđịnh nghĩa phương thức sau:- find(obj[, name][, module][, globs][, extraglobs])¶
Trả về danh sách
DocTests được xác định bởi chuỗi tài liệu của obj hoặc bởi bất kỳ chuỗi tài liệu nào của đối tượng chứa nó.Đối số tùy chọn name chỉ định tên của đối tượng; tên này sẽ được sử dụng để tạo tên cho
DocTests được trả về. Nếu name không được chỉ định thìobj.__name__sẽ được sử dụng.Tham số tùy chọn module là mô-đun chứa đối tượng đã cho. Nếu mô-đun không được chỉ định hoặc là
Nonethì công cụ tìm kiếm sẽ cố gắng tự động xác định đúng mô-đun. Mô-đun của đối tượng được sử dụng:Là không gian tên mặc định, nếu globs không được chỉ định.
Để ngăn DocTestFinder trích xuất DocTest từ các đối tượng được nhập từ các mô-đun khác. (Các đối tượng chứa mô-đun không phải là module sẽ bị bỏ qua.)
Để tìm tên của tập tin chứa đối tượng.
Để giúp tìm số dòng của đối tượng trong tệp của nó.
Nếu module là
Falsethì sẽ không có nỗ lực tìm kiếm mô-đun nào được thực hiện. Điều này không rõ ràng, chủ yếu được sử dụng trong việc kiểm tra doctest: nếu module làFalsehoặc làNonenhưng không thể được tìm thấy tự động, thì tất cả các đối tượng được coi là thuộc về mô-đun (không tồn tại), vì vậy tất cả các đối tượng được chứa sẽ được tìm kiếm (đệ quy) để tìm doctest.Các giá trị chung cho mỗi
DocTestđược hình thành bằng cách kết hợp globs và extraglobs (các liên kết trong extraglobs ghi đè các liên kết trong globs). Một bản sao nông mới của từ điển toàn cầu được tạo cho mỗiDocTest. Nếu globs không được chỉ định thì nó sẽ mặc định là__dict__của mô-đun nếu được chỉ định hoặc{}nếu không. Nếu extraglobs không được chỉ định thì mặc định là{}.
Đối tượng DocTestParser¶
- class doctest.DocTestParser¶
Một lớp xử lý được sử dụng để trích xuất các ví dụ tương tác từ một chuỗi và sử dụng chúng để tạo đối tượng
DocTest.DocTestParserđịnh nghĩa các phương thức sau:- get_doctest(string, globs, name, filename, lineno)¶
Trích xuất tất cả các ví dụ doctest từ chuỗi đã cho và thu thập chúng vào đối tượng
DocTest.globs, name, filename và lineno là các thuộc tính cho đối tượng
DocTestmới. Xem tài liệu vềDocTestđể biết thêm thông tin.
Đối tượng TestResults¶
Đối tượng DocTestRunner¶
- class doctest.DocTestRunner(checker=None, verbose=None, optionflags=0)¶
Lớp xử lý được sử dụng để thực thi và xác minh các ví dụ tương tác trong
DocTest.Việc so sánh giữa kết quả đầu ra dự kiến và kết quả đầu ra thực tế được thực hiện bởi
OutputChecker. Sự so sánh này có thể được tùy chỉnh bằng một số cờ tùy chọn; xem phần Cờ tùy chọn để biết thêm thông tin. Nếu cờ tùy chọn không đủ thì việc so sánh cũng có thể được tùy chỉnh bằng cách chuyển một lớp con củaOutputCheckercho hàm tạo.Đầu ra màn hình của người chạy thử có thể được điều khiển theo hai cách. Đầu tiên, một hàm đầu ra có thể được chuyển tới
run(); hàm này sẽ được gọi với các chuỗi sẽ được hiển thị. Nó mặc định làsys.stdout.write. Nếu việc thu thập đầu ra là không đủ thì đầu ra màn hình cũng có thể được tùy chỉnh bằng cách phân lớp con DocTestRunner và ghi đè các phương thứcreport_start(),report_success(),report_unexpected_exception()vàreport_failure().Đối số từ khóa tùy chọn checker chỉ định đối tượng
OutputChecker(hoặc thay thế thả vào) sẽ được sử dụng để so sánh kết quả đầu ra dự kiến với kết quả đầu ra thực tế của các ví dụ doctest.Đối số từ khóa tùy chọn verbose kiểm soát mức độ chi tiết của
DocTestRunner. Nếu verbose làTruethì thông tin sẽ được in về từng ví dụ khi nó được chạy. Nếu verbose làFalsethì chỉ in lỗi. Nếu verbose không được chỉ định hoặcNonethì đầu ra chi tiết sẽ được sử dụng nếu sử dụng khóa chuyển dòng lệnh-v.Đối số từ khóa tùy chọn optionflags có thể được sử dụng để kiểm soát cách người chạy thử so sánh đầu ra dự kiến với đầu ra thực tế và cách nó hiển thị các lỗi. Để biết thêm thông tin, xem phần Cờ tùy chọn.
Người chạy thử tích lũy số liệu thống kê. Số lượng tổng hợp các ví dụ đã thử, không thành công và bị bỏ qua cũng có sẵn thông qua các thuộc tính
tries,failuresvàskips. Các phương thứcrun()vàsummarize()trả về một phiên bảnTestResults.DocTestRunnerđịnh nghĩa các phương thức sau:- report_start(out, test, example)¶
Báo cáo rằng người chạy thử sắp xử lý ví dụ đã cho. Phương thức này được cung cấp để cho phép các lớp con của
DocTestRunnertùy chỉnh đầu ra của chúng; nó không nên được gọi trực tiếp.example là ví dụ sắp được xử lý. test là bài kiểm tra có chứa example. out là hàm đầu ra được truyền cho
DocTestRunner.run().
- report_success(out, test, example, got)¶
Báo cáo rằng ví dụ đã cho đã chạy thành công. Phương thức này được cung cấp để cho phép các lớp con của
DocTestRunnertùy chỉnh đầu ra của chúng; nó không nên được gọi trực tiếp.example là ví dụ sắp được xử lý. got là đầu ra thực tế từ ví dụ. test là bài kiểm tra có chứa example. out là hàm đầu ra được truyền cho
DocTestRunner.run().
- report_failure(out, test, example, got)¶
Báo cáo rằng ví dụ đã cho không thành công. Phương thức này được cung cấp để cho phép các lớp con của
DocTestRunnertùy chỉnh đầu ra của chúng; nó không nên được gọi trực tiếp.example là ví dụ sắp được xử lý. got là đầu ra thực tế từ ví dụ. test là bài kiểm tra có chứa example. out là hàm đầu ra được truyền cho
DocTestRunner.run().
- report_unexpected_exception(out, test, example, exc_info)¶
Báo cáo rằng ví dụ đã cho đưa ra một ngoại lệ không mong muốn. Phương thức này được cung cấp để cho phép các lớp con của
DocTestRunnertùy chỉnh đầu ra của chúng; nó không nên được gọi trực tiếp.example là ví dụ sắp được xử lý. exc_info là một bộ chứa thông tin về ngoại lệ không mong muốn (được trả về bởi
sys.exc_info()). test là bài kiểm tra có chứa example. out là hàm đầu ra được truyền choDocTestRunner.run().
- run(test, compileflags=None, out=None, clear_globs=True)¶
Chạy các ví dụ trong test (đối tượng
DocTest) và hiển thị kết quả bằng hàm ghi out. Trả về một phiên bảnTestResults.Các ví dụ được chạy trong không gian tên
test.globs. Nếu clear_globs là true (mặc định), thì vùng tên này sẽ bị xóa sau khi chạy thử để hỗ trợ việc thu gom rác. Nếu bạn muốn kiểm tra không gian tên sau khi quá trình kiểm tra hoàn tất, hãy sử dụng clear_globs=False.compileflags cung cấp bộ cờ mà trình biên dịch Python sẽ sử dụng khi chạy các ví dụ. Nếu không được chỉ định thì nó sẽ mặc định tập hợp các cờ nhập trong tương lai áp dụng cho globs.
Đầu ra của mỗi ví dụ được kiểm tra bằng trình kiểm tra đầu ra của
DocTestRunnervà kết quả được định dạng bằng phương thứcDocTestRunner.report_*().
- summarize(verbose=None)¶
In bản tóm tắt tất cả các trường hợp thử nghiệm đã được DocTestRunner này chạy và trả về một phiên bản
TestResults.Đối số verbose tùy chọn kiểm soát mức độ chi tiết của bản tóm tắt. Nếu mức độ chi tiết không được chỉ định thì mức độ chi tiết của
DocTestRunnersẽ được sử dụng.
DocTestParsercó các thuộc tính sau:- tries¶
Số lượng ví dụ đã thử.
- failures¶
Số lượng ví dụ thất bại
- skips¶
Số lượng ví dụ bị bỏ qua
Added in version 3.13.
Đối tượng OutputChecker¶
- class doctest.OutputChecker¶
Một lớp được sử dụng để kiểm tra xem đầu ra thực tế từ một ví dụ doctest có khớp với đầu ra dự kiến hay không.
OutputCheckerxác định hai phương thức:check_output(), so sánh một cặp đầu ra nhất định và trả vềTruenếu chúng khớp; vàoutput_difference(), trả về một chuỗi mô tả sự khác biệt giữa hai kết quả đầu ra.OutputCheckerđịnh nghĩa các phương thức sau:- check_output(want, got, optionflags)¶
Trả về
Truenếu đầu ra thực tế từ một ví dụ (got) khớp với đầu ra dự kiến (want). Các chuỗi này luôn được coi là khớp nếu chúng giống hệt nhau; nhưng tùy thuộc vào cờ tùy chọn mà người chạy thử nghiệm đang sử dụng, cũng có thể có một số loại kết quả không chính xác. Xem phần Cờ tùy chọn để biết thêm thông tin về cờ tùy chọn.
- output_difference(example, got, optionflags)¶
Trả về một chuỗi mô tả sự khác biệt giữa kết quả đầu ra dự kiến của một ví dụ nhất định (example) và kết quả đầu ra thực tế (got). optionflags là tập hợp các cờ tùy chọn được sử dụng để so sánh want và got.
Gỡ lỗi¶
Doctest cung cấp một số cơ chế để gỡ lỗi các ví dụ doctest:
Một số hàm chuyển đổi doctest thành các chương trình Python có thể thực thi được, có thể chạy trong trình gỡ lỗi Python,
pdb.Lớp
DebugRunnerlà lớp con củaDocTestRunnerđưa ra một ngoại lệ cho ví dụ bị lỗi đầu tiên, chứa thông tin về ví dụ đó. Thông tin này có thể được sử dụng để thực hiện gỡ lỗi sau khi thử nghiệm trên ví dụ.Các trường hợp
unittestđược tạo bởiDocTestSuite()hỗ trợ phương thứcdebug()được xác định bởiunittest.TestCase.Bạn có thể thêm lệnh gọi tới
pdb.set_trace()trong một ví dụ tốt nhất và bạn sẽ truy cập trình gỡ lỗi Python khi dòng đó được thực thi. Sau đó, bạn có thể kiểm tra giá trị hiện tại của các biến, v.v. Ví dụ: giả sửa.pychỉ chứa chuỗi tài liệu mô-đun này""" >>> định nghĩa f(x): ...g(x*2) >>> định nghĩa g(x): ... in(x+3) ... nhập pdb; pdb.set_trace() >>>f(3) 9 """
Sau đó, phiên Python tương tác có thể trông như thế này:
>>> nhập a, doctest >>> doctest.testmod(a) --Trở về-- > <doctest a[1]>(3)g()->Không có -> nhập pdb; pdb.set_trace() (Pdb) danh sách 1 độ phân giải g(x): 2 bản in(x+3) 3 -> nhập pdb; pdb.set_trace() [EOF] (Pdb) p x 6 (Pdb) bước --Trở về-- > <doctest a[0]>(2)f()->Không có ->g(x*2) (Pdb) danh sách 1 xác định f(x): 2 -> g(x*2) [EOF] (Pdb) p x 3 (Pdb) bước --Trở về-- > <doctest a[2]>(1)?()->Không có -> f(3) (Pdb) tiếp (0, 3) >>>
Các hàm chuyển đổi doctest thành mã Python và có thể chạy mã tổng hợp trong trình gỡ lỗi:
- doctest.script_from_examples(s)¶
Chuyển đổi văn bản có ví dụ thành tập lệnh.
Đối số s là một chuỗi chứa các ví dụ tốt nhất. Chuỗi được chuyển đổi thành tập lệnh Python, trong đó các ví dụ doctest trong s được chuyển đổi thành mã thông thường và mọi thứ khác được chuyển đổi thành nhận xét Python. Tập lệnh được tạo sẽ được trả về dưới dạng chuỗi. Ví dụ::
nhập doctest print(doctest.script_from_examples(r""" Đặt x và y thành 1 và 2. >>> x, y = 1, 2 In tổng của chúng: >>> in(x+y) 3 """))
hiển thị:
# Set x và y thành 1 và 2. x, y = 1, 2 # # Print tổng của họ: in(x+y) # Expected: ## 3
Hàm này được các hàm khác sử dụng nội bộ (xem bên dưới), nhưng cũng có thể hữu ích khi bạn muốn chuyển đổi phiên Python tương tác thành tập lệnh Python.
- doctest.testsource(module, name)¶
Chuyển đổi doctest của một đối tượng thành một tập lệnh.
Đối số module là một đối tượng mô-đun hoặc tên có dấu chấm của một mô-đun, chứa đối tượng mà các doctest được quan tâm. Đối số name là tên (trong mô-đun) của đối tượng có tài liệu quan tâm. Kết quả là một chuỗi chứa chuỗi tài liệu của đối tượng được chuyển đổi thành tập lệnh Python, như được mô tả cho
script_from_examples()ở trên. Ví dụ: nếu mô-đuna.pychứa hàm cấp cao nhấtf(), thìnhập một, doctest print(doctest.testsource(a, "a.f"))
in một phiên bản tập lệnh của chuỗi tài liệu của hàm
f(), với các doctest được chuyển đổi thành mã và phần còn lại được đặt trong các nhận xét.
- doctest.debug(module, name, pm=False)¶
Gỡ lỗi các tài liệu cho một đối tượng.
Các đối số module và name giống như đối với hàm
testsource()ở trên. Tập lệnh Python tổng hợp cho chuỗi tài liệu của đối tượng được đặt tên được ghi vào một tệp tạm thời và sau đó tệp đó được chạy dưới sự kiểm soát của trình gỡ lỗi Python,pdb.Một bản sao nông của
module.__dict__được sử dụng cho cả bối cảnh thực thi cục bộ và toàn cục.Đối số tùy chọn pm kiểm soát xem có sử dụng tính năng gỡ lỗi sau khi chết hay không. Nếu pm có giá trị thực, tệp tập lệnh sẽ được chạy trực tiếp và trình gỡ lỗi chỉ được tham gia nếu tập lệnh kết thúc bằng cách đưa ra một ngoại lệ chưa được xử lý. Nếu đúng như vậy thì việc gỡ lỗi sau khi xử lý sẽ được thực hiện, thông qua
pdb.post_mortem(), chuyển đối tượng truy nguyên từ ngoại lệ chưa được xử lý. Nếu pm không được chỉ định hoặc sai, tập lệnh sẽ được chạy trong trình gỡ lỗi ngay từ đầu, thông qua việc chuyển lệnh gọiexec()thích hợp tớipdb.run().
- doctest.debug_src(src, pm=False, globs=None)¶
Gỡ lỗi các tài liệu trong một chuỗi.
Điều này giống như hàm
debug()ở trên, ngoại trừ một chuỗi chứa các ví dụ doctest được chỉ định trực tiếp, thông qua đối số src.Đối số tùy chọn pm có ý nghĩa tương tự như trong hàm
debug()ở trên.Đối số tùy chọn globs cung cấp một từ điển để sử dụng làm bối cảnh thực thi cục bộ và toàn cục. Nếu không được chỉ định hoặc
None, một từ điển trống sẽ được sử dụng. Nếu được chỉ định, một bản sao nông của từ điển sẽ được sử dụng.
Lớp DebugRunner và các ngoại lệ đặc biệt mà nó có thể nêu ra, được các tác giả khung thử nghiệm quan tâm nhất và sẽ chỉ được phác thảo ở đây. Xem mã nguồn và đặc biệt là chuỗi doc của DebugRunner (là doctest!) để biết thêm chi tiết:
- class doctest.DebugRunner(checker=None, verbose=None, optionflags=0)¶
Một lớp con của
DocTestRunnerđưa ra một ngoại lệ ngay khi gặp lỗi. Nếu một ngoại lệ không mong muốn xảy ra, một ngoại lệUnexpectedExceptionsẽ được đưa ra, chứa bài kiểm tra, ví dụ và ngoại lệ ban đầu. Nếu đầu ra không khớp thì ngoại lệDocTestFailuresẽ được đưa ra, chứa thử nghiệm, ví dụ và đầu ra thực tế.Để biết thông tin về các tham số và phương thức của hàm tạo, hãy xem tài liệu về
DocTestRunnertrong phần API nâng cao.
Có hai trường hợp ngoại lệ có thể được đưa ra bởi các phiên bản DebugRunner:
- exception doctest.DocTestFailure(test, example, got)¶
Một ngoại lệ do
DocTestRunnerđưa ra để báo hiệu rằng kết quả thực tế của một ví dụ doctest không khớp với kết quả mong đợi của nó. Các đối số của hàm tạo được sử dụng để khởi tạo các thuộc tính có cùng tên.
DocTestFailure xác định các thuộc tính sau:
- DocTestFailure.example¶
Zz000zz bị lỗi.
- DocTestFailure.got¶
Đầu ra thực tế của ví dụ.
- exception doctest.UnexpectedException(test, example, exc_info)¶
Một ngoại lệ do
DocTestRunnerđưa ra để báo hiệu rằng một ví dụ tốt nhất đã đưa ra một ngoại lệ không mong muốn. Các đối số của hàm tạo được sử dụng để khởi tạo các thuộc tính có cùng tên.
UnexpectedException xác định các thuộc tính sau:
- UnexpectedException.example¶
Zz000zz bị lỗi.
- UnexpectedException.exc_info¶
Một bộ chứa thông tin về ngoại lệ không mong muốn được trả về bởi
sys.exc_info().
hộp xà phòng¶
Như đã đề cập trong phần giới thiệu, doctest đã phát triển với ba mục đích sử dụng chính:
Kiểm tra các ví dụ trong tài liệu.
Kiểm tra hồi quy.
Tài liệu có thể thực thi/kiểm tra khả năng đọc viết.
Những mục đích sử dụng này có những yêu cầu khác nhau và điều quan trọng là phải phân biệt chúng. Đặc biệt, việc lấp đầy chuỗi tài liệu của bạn bằng các trường hợp kiểm thử khó hiểu sẽ tạo ra tài liệu tồi.
Khi viết một chuỗi tài liệu, hãy cẩn thận khi chọn các ví dụ về chuỗi tài liệu. Có một nghệ thuật trong việc này cần phải học --- ban đầu nó có thể không tự nhiên. Các ví dụ nên thêm giá trị đích thực vào tài liệu. Một ví dụ điển hình thường có giá trị bằng nhiều lời nói. Nếu được thực hiện cẩn thận, các ví dụ sẽ là vô giá đối với người dùng của bạn và sẽ mang lại lợi ích gấp nhiều lần cho thời gian cần thiết để thu thập chúng khi năm tháng trôi qua và mọi thứ thay đổi. Tôi vẫn ngạc nhiên về tần suất một trong các ví dụ doctest của tôi ngừng hoạt động sau một thay đổi "vô hại".
Doctest cũng tạo ra một công cụ tuyệt vời để kiểm tra hồi quy, đặc biệt nếu bạn không tiết kiệm văn bản giải thích. Bằng cách xen kẽ văn xuôi và ví dụ, việc theo dõi những gì thực sự đang được thử nghiệm và tại sao sẽ trở nên dễ dàng hơn nhiều. Khi thử nghiệm thất bại, văn xuôi tốt có thể giúp bạn dễ dàng tìm ra vấn đề là gì và cách khắc phục. Đúng là bạn có thể viết những bình luận sâu rộng trong thử nghiệm dựa trên mã, nhưng rất ít lập trình viên làm được điều đó. Nhiều người đã phát hiện ra rằng việc sử dụng các phương pháp doctest sẽ dẫn đến các bài kiểm tra rõ ràng hơn nhiều. Có lẽ điều này đơn giản là do doctest làm cho việc viết văn xuôi dễ hơn viết mã một chút, trong khi viết nhận xét bằng mã khó hơn một chút. Tôi nghĩ nó còn sâu xa hơn thế: thái độ tự nhiên khi viết một bài kiểm tra dựa trên doctest là bạn muốn giải thích những điểm hay của phần mềm và minh họa chúng bằng các ví dụ. Điều này tự nhiên dẫn đến các tệp thử nghiệm bắt đầu với các tính năng đơn giản nhất và tiến triển một cách hợp lý đến các trường hợp phức tạp và khó khăn. Kết quả là một câu chuyện mạch lạc, thay vì một tập hợp các chức năng riêng biệt kiểm tra các phần chức năng riêng biệt dường như ngẫu nhiên. Đó là một thái độ khác và tạo ra những kết quả khác, làm mờ đi sự khác biệt giữa kiểm tra và giải thích.
Kiểm tra hồi quy tốt nhất nên giới hạn ở các đối tượng hoặc tệp chuyên dụng. Có một số lựa chọn để tổ chức kiểm tra:
Viết các tệp văn bản chứa các trường hợp kiểm thử làm ví dụ tương tác và kiểm tra các tệp bằng
testfile()hoặcDocFileSuite(). Điều này được khuyến khích, mặc dù đây là cách dễ thực hiện nhất đối với các dự án mới, được thiết kế ngay từ đầu để sử dụng doctest.Xác định các hàm có tên
_regrtest_topicbao gồm các chuỗi tài liệu đơn lẻ, chứa các trường hợp thử nghiệm cho các chủ đề được đặt tên. Các chức năng này có thể được bao gồm trong cùng một tệp với mô-đun hoặc được tách thành một tệp thử nghiệm riêng.Xác định ánh xạ từ điển
__test__từ các chủ đề kiểm tra hồi quy đến các chuỗi tài liệu chứa các trường hợp kiểm tra.
Khi bạn đã đặt các bài kiểm thử của mình vào một mô-đun, chính mô-đun đó có thể là trình chạy thử nghiệm. Khi kiểm thử thất bại, bạn có thể sắp xếp để người chạy thử chỉ chạy lại doctest bị lỗi trong khi bạn gỡ lỗi. Đây là một ví dụ tối thiểu về một người chạy thử nghiệm như vậy:
nếu __name__ == '__main__':
nhập doctest
cờ = doctest.REPORT_NDIFF|doctest.FAIL_FAST
nếu len(sys.argv) > 1:
tên = sys.argv[1]
nếu tên trong toàn cầu():
obj = toàn cầu() [tên]
khác:
obj = __test__[tên]
doctest.run_docstring_examples(obj, Globals(), name=name,
optionflags=cờ)
khác:
thất bại, tổng cộng = doctest.testmod(optionflags=flags)
print(f"{fail} lỗi trong tổng số {total} lần kiểm tra")
Chú thích cuối trang