Các công cụ sửa lỗi là trung tâm của bất kỳ ngôn ngữ lập trình nào.
Và với tư cách là nhà phát triển, thật khó để đạt được tiến bộ và viết mã sạch trừ khi bạn biết cách sử dụng các công cụ này.
Bài viết này sẽ giúp bạn làm quen với một công cụ như vậy: Trình gỡ lỗi Python (pdb)
Lưu ý rằng đây là hướng dẫn sửa lỗi. Tôi cho rằng bạn đã quen thuộc với ít nhất một ngôn ngữ lập trình và có ý tưởng về việc viết các ca kiểm thử.
Có hai cách để gọi pdb
:
1. Gọi pdb
bên ngoài
Để gọi pdb
khi ở trên một thiết bị đầu cuối, bạn có thể gọi nó trong khi thực hiện .py
tập tin.
python -m pdb <test-file-name>.py
Nếu bạn sử dụng thơ và pytest, bạn có thể gọi pdb
sử dụng --pdb
cờ cuối cùng.
poetry run python <path/to_your/test_file.py> --pdb
Để gọi pdb
với docker, poetry
và pytest
bạn có thể sử dụng cú pháp sau:
COMPOSE_PROJECT_NAME=<test_docker_image_name> docker-compose run --rm workers poetry run pytest <path/to_your/test_file.py>::<name_of_the_test_function> --pdb
Bạn sẽ luôn thêm --pdb
gắn cờ sau tên tệp thử nghiệm của bạn. Điều này sẽ mở pdb
bảng điều khiển khi thử nghiệm bị hỏng. Nhưng hãy nhớ --pdb
là một pytest
lá cờ.
2. Thêm điểm dừng với pdb
Có thể có trường hợp bạn nhận được (các) kết quả dương tính giả trong xét nghiệm. Trường hợp thử nghiệm của bạn có thể vượt qua nhưng bạn không nhận được dữ liệu như mong đợi.
Nếu bạn muốn đọc truy vấn cơ sở dữ liệu thô thì sao? Trong trường hợp đó bạn có thể gọi pdb
từ bên trong hàm Python.
Để đột nhập vào pdb
trình gỡ lỗi, bạn cần gọi import pdb; pdb.set_trace()
bên trong chức năng của bạn.
Hãy hiểu điều này với một ví dụ về hàm lồng nhau:
# file1.py
from . import function3
def function1():
// logic for function1
function3()
# file2.py
def function2():
// logic for function2
// some database query
# file3.py
from . import function2
def function3():
// logic for function3
function2()
// logic for function3 continues
Trong đoạn mã trên, một chức năng gọi một chức năng khác.
Bạn muốn thêm một điểm dừng trong function2
để hiểu những gì đang thực sự xảy ra trong chức năng.
Bạn có thể thêm một điểm ngắt với câu lệnh sau:
import pdb; pdb.set_trace()
# file2.py
1. def function2():
2. // logic for function2
3. // line 1
4. // line 2
5.
6. import pdb; pdb.set_trace();
7.
8. // some database query
9. // line 3
10. // line 4
pdb
mở bảng điều khiển của nó khi mã của bạn bị hỏng. Một cái gì đó như thế này:
(Pdb)
Khi trình thông dịch Python thực thi line2
nó sẽ đọc điểm ngắt và mở pdb
bảng điều khiển. Chúng tôi sử dụng pdb
các lệnh để điều hướng mã. Chúng ta sẽ tìm hiểu các lệnh này trong phần tiếp theo.
pdb
là một trình gỡ lỗi dòng lệnh tương tác. Bạn không thể khai thác hết tiềm năng của nó trừ khi bạn quen thuộc với các lệnh của nó.
Giống như mọi nhật ký bảng điều khiển khác, pdb
sẽ cho bạn biết chính xác mã của bạn bị hỏng ở dòng nào.
Lệnh in
Giả sử bạn có một trường hợp thử nghiệm với một assert
bản tường trình. Một cái gì đó như thế này:
# test.py
def test1():
...
result = function1()
assert result.json = {'status_code':1, 'status': 'saved', 'description':'data saved'}
Bạn sẽ sử dụng p
lệnh in một giá trị ra bàn điều khiển.
(Pdb) p result.json
{'status_code':1, 'status': 'saved', 'description':'data saved'}
Điều này in ra giá trị mà biến nắm giữ.
Lệnh lên
Lệnh up di chuyển bạn lên một khung hình trong ngăn xếp.
Trong trường hợp các lệnh gọi hàm lồng nhau, nó sẽ chuyển bạn đến hàm đã gọi hàm của bạn.
Hãy lấy một ví dụ:
# test.py
def function1():
print("invoking function1")
import pdb;pdb.set_trace()
print("function1 invoked")
def function2():
print("invoking function2")
function1()
print("function2 invoked")
def function3():
print("inside function3")
function2()
print("function3 invoked")
# starting the call with function2()
function3()
Trong pdb
chúng tôi sẽ gọi nó theo cách này:
$ python -m pdb test.py
> test.py(1)<module>()
-> def function1():
(Pdb) n
> test.py(7)<module>()
-> def function2():
(Pdb) n
> test.py(13)<module>()
-> def function3():
(Pdb) n
> test.py(20)<module>()
-> function3()
(Pdb) n
inside function3
invoking function2
invoking function1
> test.py(4)function1()
-> print("function1 invoked")
(Pdb) n
function1 invoked
--Return--
> test.py(4)function1()->None
-> print("function1 invoked")
(Pdb) u
> test.py(9)function2()
-> function1()
(Pdb) l
4 print("function1 invoked")
5
6
7 def function2():
8 print("invoking function2")
9 -> function1()
10 print("function2 invoked")
11
12
13 def function3():
14 print("inside function3")
(Pdb) u
> test.py(15)function3()
-> function2()
(Pdb) l
10 print("function2 invoked")
11
12
13 def function3():
14 print("inside function3")
15 -> function2()
16 print("function3 invoked")
17
18 # starting the call with function2()
19
20 function3()
(Pdb) u
> test.py(20)<module>()
-> function3()
(Pdb) l
15 function2()
16 print("function3 invoked")
17
18 # starting the call with function2()
19
20 -> function3()
[EOF]
(Pdb) u
> <string>(1)<module>()
Ở đây chúng tôi bắt đầu với việc gọi function3()
. Việc thực hiện dừng lại khi nó gặp import pdb
.
pdb
mở bàn điều khiển và đợi đầu vào. chúng tôi gõ u
for up, và nó trả về hàm gọi: function2()
. Ở phần tiếp theo u
lệnh nó trả về function3
(hàm gọi function2
).
chúng tôi đang sử dụng l
chỉ huy. Đó là lệnh liệt kê. Nó liệt kê chính xác vị trí của dòng thực thi hiện tại.
Lệnh bước
Để hiểu được step
lệnh, hãy tiếp tục với ví dụ trước.
# test.py
1. def test1():
2. ...
3. result = function1()
4. assert result.json.status_code == 1
5. assert result.json.status == 'saved'
6. assert result.json.description == 'data saved'
7.
# function_file.py
def function1():
foo = ['bar']
...
Bạn nghi ngờ rằng kết quả trả về từ function1()
là không chính xác. Mã của bạn bắt đầu ở dòng 6. Làm cách nào để bạn chuyển sang dòng 3?
Bạn sẽ sử dụng up
lệnh đầu tiên và cuối cùng bước vào chức năng với s
chỉ huy.
(Pdb) u
assert result.json.status == 'saved'
(Pdb) u
assert result.json.status_code == 1
(Pdb) p assert result.json.status_code
1
(Pdb) u
result = function1()
(Pdb) s
(Pdb) n
foo = ['bar']
Khi bạn bước vào function1()
các pdb
bảng điều khiển sẽ bắt đầu in các câu lệnh từ chức năng đó.
pdb
là một trình sửa lỗi mạnh mẽ. Hướng dẫn này nhằm giúp bạn làm quen với pdb
cơ bản.
Tôi khuyên bạn nên đọc tài liệu của nó để khám phá toàn bộ tiềm năng.