Bài giảng Kỹ thuật lập trình - Bài 9: Gỡ lỗi và kiểm thử - Trịnh Thành Trung
Nội dung
1. Gỡ lỗi
2. Kiểm thử
1.
Gỡ lỗi
Debug
Gỡ rối
Debug
▪ Gỡ rối là gì?
▫ Khi chương trình bị lỗi, gỡ rối là các công việc cần làm để làm
cho chương trình dịch thông, chạy thông
▫ Thật không may, gỡ rối luôn là thao tác phải làm khi lập trình,
thao tác này rất tốn kém
▪ Cách tốt nhất vẫn là phòng ngừa
▫ Khi bắt đầu gỡ rối chương trình, bạn đã biết là chương trình
không chạy.
▫ Nếu bạn biết lý do tại sao chương trình không chạy, bạn có thể
sửa được chương trình cho nó chạy
▫ Nếu bạn hiểu chương trình của bạn, bạn sẽ có ít sai lầm và dễ
dàng sửa chữa sai sót hơn. Bí quyết là viết mã đơn giản, hiệu quả,
Gỡ rối
Debug
▪ Đối với mã nguồn, tiêu chí nào quan trọng hơn: rõ ràng hay
chính xác?
▫ Nếu mã nguồn rõ ràng, bạn có thể làm cho chương trình trở nên
chính xác.
▫ Bạn có chắc là làm cho chương trình trở nên chính xác nếu nó
không rõ ràng hay không?
▪ Nếu chương trình được thiết kế với cấu trúc tốt, được viết
bằng phong cách lập trình tốt và áp dụng các kỹ thuật viết
chương trình hiệu quả, bẫy lỗi thì chi phí cho việc gỡ rối sẽ
được giảm thiểu.
Tìm kiếm và
gỡ rối
▪ Khi có lỗi, ta thường đổ cho trình dịch, thư viện hay bất cứ
nguyên nhân khách quan nào khác… tuy nhiên, cuối cùng thì
lỗi vẫn là lỗi của chương trình, và trách nhiệm gỡ rối thuộc về
LTV
▪ Phải hiểu vấn đề xuất phát từ đâu thì mới giải quyết được:
▫ Lỗi xảy ra ở đâu? Hầu hết các lỗi thường đơn giản và dễ tìm.
Hãy khảo sát các đầu mối và cố gắng xác định được đoạn mã
nguồn gây lỗi
▫ Lỗi xảy ra như thế nào? Khi đã có một số thông tin về lỗi và nơi
xảy ra lỗi, hãy suy nghĩ xem lỗi xảy ra như thế nào
▫ Đâu là nguyên nhân gây lỗi? Suy luận ngược trở lại trạng thái
của chương trình để xác định nguyên nhân gây ra lỗi
Gỡ rối liên quan đến việc suy
luận lùi, giỗng như phá án. Một
số vấn đề không thể xảy ra và chỉ
có những thông tin xác thực mới
đáng tin cậy. Phải đi ngược từ kết
quả để khám phá nguyên nhân.
Khi có lời giải thích đầy đủ, ta sẽ
biết được vấn đề cần sửa và có
thể phát hiện ra một số vấn đề
khác
“
Debugging
Heuristic
Debugging Heuristic
Áp dụng khi nào
Build-time (dịch)
(1) Hiểu các thông báo lỗi (error messages)
(2) Nghĩ trước khi viết lại chương trình
(3) Tìm kiếm các lỗi (bug) hay xảy ra
(4) Divide and conquer
(5) Viết thêm các đoạn mã kiểm tra để
chương trình tự kiểm tra nó
Run-time (chạy)
(6) Hiện thị kết quả
(7) Sử dụng debugger
(8) Tập trung vào các lệnh mới viết / mới viết
lại
Hiểu
các thông báo lỗi
▪ Gỡ rối khi dịch (build-time) chương trình dễ hơn gỡ rối khi
chạy chương trình nếu LTV hiểu được các thông báo lỗi
▪ Một số thông báo lỗi đến từ preprocessor
#include <stdioo.h>
int main(void)
Gõ sai tên file cần gọi
/* Print "hello, world" to stdout and
return 0.
Thiếu dấu */
{
printf("hello, world\n");
return 0;
}
$ gcc217 hello.c -o hello
hello.c:1:20: stdioo.h: No such file or directory
hello.c:3:1: unterminated comment
hello.c:2: error: syntax error at end of input
Hiểu
các thông báo lỗi
▪ Một số thông báo lỗi đến từ compiler
#include <stdio.h>
int main(void)
/* Print "hello, world" to stdout and
return 0. */
{
Sai từ khóa
printf("hello, world\n")
retun 0;
}
$ gcc217 hello.c -o hello
hello.c: In function `main':
hello.c:7: error: `retun' undeclared (first use in this function)
hello.c:7: error: (Each undeclared identifier is reported only once
hello.c:7: error: for each function it appears in.)
hello.c:7: error: syntax error before numeric constant
Hiểu
các thông báo lỗi
▪ Một số thông báo lỗi đến từ linker
Sai tên hàm
được gọi
#include <stdio.h>
int main(void)
/* Print "hello, world" to stdout and
return 0. */
{
prinf("hello, world\n")
return 0;
}
Compiler warning (not error): prinf()
được gọi trước khi khai báo
Linker error: không tìm thấy
định nghĩa hàm prinf()
$ gcc217 hello.c -o hello
hello.c: In function `main':
hello.c:6: warning: implicit declaration of function `prinf'
/tmp/cc43ebjk.o(.text+0x25): In function `main':
: undefined reference to `prinf'
collect2: ld returned 1 exit status
Việc thay đổi mã nguồn không
hợp lý có thể gây ra nhiều vấn
đề hơn là để nguyên không thay
đổi gì, do đó phải luôn suy nghĩ
trước khi làm
“
Suy nghĩ
trước khi viết
▪ Gỡ rối ngay khi gặp
▫ Khi phát hiện lỗi, hãy sửa ngay, đừng để sau mới sửa, vì có thể
lỗi không xuất hiện lại (do tình huống)
▫ Cân nhắc: việc sửa chữa này có ảnh hưởng tới các tình huống
khác hay không ?
▪ Quan sát lỗi từ góc độ khác
▫ Viết đoạn mã nguồn gây lỗi ra giấy
▸ Đừng chép hết cả đoạn không có nguy cơ gây lỗi, hoặc in toàn bộ
code ra giấy in => phá vỡ cây cấu trúc
▫ Vẽ hình minh họa các cấu trúc dữ liệu
▸ Nếu mà giải thuật làm thay đổi CTDL, vẽ lại hình trước khi viết lại
giải thuật
▫ Đọc trước khi gõ vào
▸ Đừng vội vàng, khi không rõ điều gì thực sự gây ra lỗi và sửa
Suy nghĩ
trước khi viết
▪ Tạm dừng viết chương trình
▫ Khi gặp vấn đề, khó khăn, chậm tiến độ, lập tức thay đổi công
việc => rút ra khỏi luồng quán tính sai lầm …
▫ Bỏ qua đoạn chương trình có lỗi
▫ Khi nào cảm thấy sẵn sàng thì chữa
▪ Giải thích logic của đoạn mã nguồn:
▫ Cho chính bạn
▸ Tạo điều kiện để suy nghĩ lại
▫ Cho ai khác có thể phản bác
▸ Extrem programming : làm việc theo cặp, pair programming,
người này LT, người kia kiểm tra, và ngược lại
▫ Cho cái gì đó không thể phản bác (cây, cốc trà đá, gấu bông…)
▸ Tạo điều kiện củng cố suy luận của mình
Tìm các lỗi
tương tự
switch (i) {
int i;
…
scanf("%d", i);
case 0:
…
/* missing break */
case 1:
…
char c;
…
break;
…
c = getchar();
}
if (i = 5)
while (c = getchar() != EOF)
…
…
Tips: nếu đặt chế độ cảnh báo
if (5 < i < 10)
if (i & j)
…
…
(warnings) khi dịch thì hầu hết
các lỗi kiểu này sẽ được phát
hiện
Tìm các lỗi
tương tự
▪ Khi gặp vấn đề, hãy liên tưởng đến những trường hợp
tương tự đã gặp
▫ Vd1 :
int n; scanf(“%d”,n); ?
▫ Vd2 :
int n=1; double d=PI;
printf(“%d %f \n”,d,n); ??
▪ Không khởi tạo biến (với C) cũng sẽ gây ra những lỗi khó
lường.
Tìm các lỗi
tương tự
▪ Làm cho lỗi xuất hiện lại
▫ Cố gắng làm cho lỗi có thể xuất hiện lại khi cần
▫ Nếu không được, thì thử tìm nguyên nhân tại sao lại không làm
cho lỗi xuất hiện lại
1. Array as a parameter handled improperly –
Tham số mảng được xử lý không đúng cách
2. Array index out of bounds – Vượt ra ngoài
phạm vi chỉ số mảng
{C/C++}
3. Call-by-value used instead of call-by
reference for function parameters to be
modified – Gọi theo giá trị, thay vì gọi theo
tham chiếu cho hàm để sửa
4. Comparison operators misused – Các toán tử
so sánh bị dùng sai
5. Compound statement not used - Lệnh phức hợp
không được dùng
6. Dangling else - nhánh else khong hợp lệ
7. Division by zero attempted - Chia cho 0
8. Division using integers so quotient gets
truncated – Dùng phép chia số nguyên nên phần
thập phân bị cắt
9. Files not closed properly (buffer not
flushed) - File không được đóng phù hợp (
buffer không bị dẹp)
10. Infinite loop - lặp vô hạn
11. Global variables used – dùng biến tổng thể
12. IF-ELSE not used properly – dùng if-else
không chuân
13. Left side of assignment not an L-value -
phía trái phép gán không phải biến
14. Loop has no body – vòng lặp không có thân
15. Missing "&" or missing "const" with a
call-by-reference
{C/C++}
function parameter – thiếu dấu & hay từ khóa
const với lời gọi tham số hàm theo tham chiếu
16. Missing bracket for body of function or
compound statement – Thiếu cặp {} cho thân của
hàm hay nhóm lệnh
17. Mission reference to namespace - Thiếu
tham chiếu tới tên miền
18. Missing return statement in a value-
returning function – Thiếu return
19. Missing semi-colon in simple statement,
function prototypes, struct definitions or
class definitions – thiếu dấu ; trong lệnh
đơn …
20. Mismatched data types in expressions –
kiểu dữ liệu không hợp
21. Operator precedence misunderstood - Hiểu
sai thứ tự các phép toán
22. Off-by-one error in a loop – Thoát khỏi
bởi 1 lỗi trong vòng lặp
23. Overused (overloaded) local variable names
- Trùng tên biến cục bộ
{C/C++}
24. Pointers not set properly or overwritten
in error – Con trỏ không được xác định đúng
hoặc trỏ vào 1 vị trí không có
25. Return with value attempted in void
function – trả về 1 giá trị trong 1 hàm void
26. Undeclared variable name – không khai báo
biến
27. Un-initialized variables – Không khởi tạo
giá trị
28. Unmatched parentheses – thiếu }
29. Un-terminated strings - xâu không kết
thúc, thiếu "
30. Using "=" when "= =" is intended or vice
versa
31. Using "&" when "&&" is intended or vice
versa
32. "while" used improperly instead of "if" –
while được dùng thay vì if
Tải về để xem bản đầy đủ
Bạn đang xem 20 trang mẫu của tài liệu "Bài giảng Kỹ thuật lập trình - Bài 9: Gỡ lỗi và kiểm thử - Trịnh Thành Trung", để tải tài liệu gốc về máy hãy click vào nút Download ở trên
File đính kèm:
bai_giang_ky_thuat_lap_trinh_bai_9_go_loi_va_kiem_thu_trinh.pdf

