3. Kiểm thử đơn vị
Công cụ kiểm thử quan trọng nhất
Kiểm thử từng phương thức đơn hoặc 1 tập
các phương thức phối hợp với nhau
Không kiểm thử chương trình tổng thể mà
kiểm thử từng lớp riêng biệt
Với mỗi lần kiểm thử, tạo 1 lớp đơn giản gọi
là dụng cụ kiểm thử (test harness)
Dụng cụ kiểm thử cung cấp tham biến cho
các phương thức được kiểm tra
2009-2010 OOP - http://mim.hus.edu.vn/elearning 3
4. Ví dụ: Tạo các dụng cụ kiểm
thử
Để tính căn bậc 2 của a dùng thuật toán sau:
Phỏng đoán 1 giá trị x có thể gần với giá trị căn
bậc 2 cần tìm (VD x = a)
Giá trị căn bậc 2 phải nằm giữa x và a/x
Thay x bằng điểm giữa (x+a/x)/2
Lặp lại quá trình trên cho đến khi 2 giá trị xấp xỉ ở
2 bước lặp liền nhau có giá trị rất gần nhau
2009-2010 OOP - http://mim.hus.edu.vn/elearning 4
5. Kiểm thử chương trình
Xem RootApproximator.java, Numeric.java,
RootApproximatorTester.java (ch10/root1)
Lớp RootApproximator có cho kết quả đúng
với với mọi dữ liệu vào?
Cần thử với nhiều giá trị
Lặp phép thử nhiều lần với dữ liệu nhập từng lần
không phải là ý tưởng hay:
Nếu có lỗi thì sau khi sửa lỗi cần nhớ các dữ liệu đã thử
để làm lại các phép thử
Giải pháp: Viết dụng cụ thử để dễ lặp lại các phép
thử đơn vị
2009-2010 OOP - http://mim.hus.edu.vn/elearning 5
6. Chuẩn bị dữ liệu vào cho kiểm
thử (1)
Có nhiều cách thức để chuẩn bị các tình
huống cho kiểm thử (test case)
Cách 1: Viết cứng các dữ liệu thử vào dụng
cụ thử
Mỗi lần phát hiện lỗi, khi sửa xong chỉ cần thực
hiện lại dụng cụ thử
Có thể đặt dữ liệu thử trong 1 tệp riêng
Xem RootApproximatorHarness1.java (ch10/root2)
2009-2010 OOP - http://mim.hus.edu.vn/elearning 6
7. Chuẩn bị dữ liệu vào cho kiểm
thử (2)
Cách 2: Tạo các tình huống thử tự động
Nếu dữ liệu vào thuộc phạm vi hẹp, có thể viết
chương trình lặp để duyệt qua 1 phần dữ liệu đại
diện
Xem RootApproximatorHarness2.java (ch10/root2)
Cách 3: Sinh ngẫu nhiên tình huống thử
Dữ liệu vào thuộc phạm vi rộng
Xem RootApproximatorHarness3.java (ch10/root2)
2009-2010 OOP - http://mim.hus.edu.vn/elearning 7
8. Chuẩn bị dữ liệu vào cho kiểm
thử (3)
Chọn các tình huống thử tốt là 1 kĩ năng quan trọng
để tìm lỗi chương trình
Xét tất cả các đặc tính của phương thức đang kiểm
thử
Xét các tình huống tiêu biểu (VD với chương trình tính căn
bậc 2: 100, ¼, 0.01, 2, 10E12)
Xét các tình huống biên: dữ liệu nằm ở phần biên của tập
giá trị cho phép (VD tính căn 0)
Người lập trình thường mắc lỗi khi xử lí các điều kiện biên: chia
cho 0, lấy kí tự từ xâu rỗng, truy cập đến con trỏ null
Xét các tình huống dữ liệu không hợp lệ (VD tính căn -2).
2009-2010 OOP - http://mim.hus.edu.vn/elearning 8
9. Đọc dữ liệu thử từ tệp
Đặt dữ liệu thử trong 1 tệp trông “đẹp” hơn.
Chuyển hướng dòng dữ liệu vào
java Program < data.txt
Một số IDE không hỗ trợ chuyển hướng dòng vào. Trong trường
hợp đó cần dùng cửa sổ lệnh
Chuyển hướng dòng dữ liệu ra:
java Program > output.txt
VD:
Xem RootApproximatorHarness4.java (ch10/root2)
Dữ liệu vào: tệp test.in
Chạy chương trình:
java RootApproximatorHarness4 < test.in > test.out
2009-2010 OOP - http://mim.hus.edu.vn/elearning 9
10. Đánh giá các tình huống thử
Làm sao biết được kết quả ra là đúng?
Tính bằng tay
Chọn các dữ liệu vào mà đã biết kết quả ra
Kiểm tra xem các kết quả ra có thoả mãn một số thuộc tính
nào đó (VD: bình phương của căn bậc hai 1 số phải bằng số
đó)
Sử dụng 1 “nhà tiên tri” (Oracle): dùng 1 phương thức chậm
hơn nhưng tin cậy để tính kết quả tương ứng (VD: Dùng
Math.pow(x, 0.5) để tính căn bậc 2).
VD:
Xem RootApproximatorHarness5.java,
RootApproximatorHarness6.java (ch10/root3)
2009-2010 OOP - http://mim.hus.edu.vn/elearning 10
11. Độ bao trùm kiểm thử
Kiểm thử hộp đen: Kiểm tra chức năng phần mềm
mà không xét đến cấu trúc cài đặt bên trong
Kiểm thử hộp trắng: Xét đến cấu trúc bên trong khi
thiết kế tình huống kiểm thử
Độ bao trùm kiểm thử (test coverage): đánh giá bao
nhiêu phần của chương trình đã được kiểm thử
Đảm bảo mỗi phần của chương trình đều được thử nghiệm
ít nhất 1 lần bởi 1 tình huống thử
VD: đảm bảo mỗi nhánh lệnh trong chương trình đều đã được
thực hiện trong ít nhất 1 tình huống thử
2009-2010 OOP - http://mim.hus.edu.vn/elearning 11
12. Kiểm thử đơn vị với JUnit
http://junit.org
Triết lí: Mỗi khi cài đặt 1 lớp thì cũng tạo ngay 1 lớp
kiểm thử đi kèm
Có trong nhiều IDE như BlueJ và Eclipse
VD:
Xem ch10/junit, chạy chương trình kiểm thử trong
BlueJ và Eclipse
2009-2010 OOP - http://mim.hus.edu.vn/elearning 12
13.
14. Theo vết chương trình
In các thông báo lần theo các bước thực hiện chương
trình
if (status == SINGLE){
System.out.println("status is SINGLE");
. . .
}
. . .
Nhược điểm: Phải bỏ các thông báo đó khi kiểm thử xong,
nếu có lỗi khác lại phải thêm các thông báo vào
Giải pháp: Dùng lớp Logger để có thể tắt đi các
thông báo vết mà không cần xoá khỏi chương trình
2009-2010 OOP - http://mim.hus.edu.vn/elearning 14
15. Ghi nhật kí (logging)
Các thông báo log có thể ngừng kích hoạt khi thực
hiện xong việc kiểm thử
Dùng đối tượng Logger.global
Ghi lại 1 thông báo:
Logger.global.info("status is SINGLE");
Ngầm định, các thông báo log được in ra. Khi cần tắt
các thông báo này dùng lệnh:
Logger.global.setLevel(Level.OFF);
Tránh log quá nhiều hoặc quá ít
Một số người lập trình thích dò lỗi (debugging) hơn
2009-2010 OOP - http://mim.hus.edu.vn/elearning 15
16. Ghi nhật kí (2)
Khi theo vết thực hiện 1 chương trình,
các sự kiện quan trọng nhất là điểm vào
và điểm ra 1 phương thức
Ở đầu phương thức, in ra giá trị các tham
biến
Ở cuối phương thức, in ra kết quả trả lại
VD: xem chương trình trong ch10/log
2009-2010 OOP - http://mim.hus.edu.vn/elearning 16
17. Sử dụng công cụ dò lỗi
(debugger)
Công cụ dò lỗi:
Cho phép chạy/tạm dừng/chạy lại 1
chương trình và phân tích các trạng thái
(giá trị các biến) trong quá trình chạy
3 khái niệm chính:
Điểm dừng (breakpoints)
Thực hiện từng bước một (single-stepping)
Khảo sát biến (inspecting variables)
2009-2010 OOP - http://mim.hus.edu.vn/elearning 17
20. Dò lỗi
Khi chạy công cụ dò lỗi một chương trình, chương trình đó được
thực hiện bình thường cho đến khi gặp dòng lệnh được đánh
dấu điểm dừng thì tạm ngừng. Khi đó, ta có thể:
Khảo sát giá trị các biến
Thực hiện từng dòng lệnh một
Hoặc tiếp tục chạy cho đến khi gặp điểm dừng sau
Khi chương trình kết thúc, công cụ dò lỗi cũng kết thúc
Các điểm dừng vẫn được kích hoạt cho đến khi bị xoá đi
Có 2 dạng lệnh chạy từng bước một:
Step Over: gặp lời gọi phương thức thì thực hiện trong 1 bước
Step Into: gặp lời gọi phương thức thì thực hiện từng lệnh một
trong phương thức đó
2009-2010 OOP - http://mim.hus.edu.vn/elearning 20
21. Ví dụ dò lỗi
Lớp Word đếm số âm tiết trong 1 từ
Mỗi cụm nguyên âm (a, e, i, o, u, y) liền nhau
được đếm là 1 âm tiết
Tuy nhiên, chữ e ở cuối từ không được đếm là 1
âm tiết
Nếu thuật toán cho giá trị đếm = 0 thì tăng thành
1
Hàm dựng bỏ đi các kí tự không phải là chữ cái ở
đầu và cuối
Xem tệp Word.java và WordTester.java
(ch10/debugger)
2009-2010 OOP - http://mim.hus.edu.vn/elearning 21
22. Thực hiện dò lỗi chương trình
Với xâu vào là "hello yellow peach.", kết quả
lỗi:
Syllables in hello: 1
Syllables in yellow: 1
Syllables in peach: 1
Đặt breakpoint vào dòng đầu tiên của phương thức
countSyllables trong lớp Word
Thực hiện chương trình, khi dừng tại breakpoint thì
thực hiện từng bước cho đến lệnh kiểm tra nếu kí tự
cuối bằng 'e'
Khảo sát biến ch chứa kí tự cuối: ch = 'l' => lỗi
2009-2010 OOP - http://mim.hus.edu.vn/elearning 22
23.
24. Các lỗi khác?
Giá trị của end = 3 chứ không phải 4
text chứa "hell" thay vì "hello"
=> countSyllables trả lại 1 là bình thường
=> lỗi nằm ở chỗ khác
Bắt đầu lại chương trình, đặt breakpoint tại đầu hàm
dựng của lớp Word.
Nhập xâu đầu vào "hello."
Ngừng lại sau khi thực hiện xong vòng lặp thứ 2 trong hàm
dựng
Khảo sát i và j: giá trị đúng
Tại sao text được đặt bằng "hell" ???
2009-2010 OOP - http://mim.hus.edu.vn/elearning 24
25.
26. Dò lỗi...
Sửa lỗi và thực hiện lại chương trình với xâu
vào ban đầu "hello yellow peach."
Còn lỗi => lặp lại quá trình dò lỗi như trên,
sửa lỗi cho đến khi thu được kết quả đúng:
Syllables in hello: 2
Syllables in yellow: 2
Syllables in peach.: 1
Đến đây có thể kết luận là chương trình đã
hết lỗi không???
2009-2010 OOP - http://mim.hus.edu.vn/elearning 26