Chúng ta sử dụng công cụ để sinh các ca kiểm thử với độ phủ cao nhất cho hàm songay
(phủ điều kiện con). Chi tiết các ca kiểm thử được hiển thị ở Hình 3.15. Tập các ca kiểm thử này sẽ được dùng để kiểm thử trên bài tập của học sinh có mã nguồn như Hình 3.16 và Hình 3.17.
Hình 3.15. Chi tiết ca kiểm thử cho tiêu chí phủ điều kiện con của hàm songay
1. int ngay=0;
2. if(((thang<0)||(thang>12))||(nam<0)||(nam>9999)){ 3. return -1; 4. }else { 5. swiTch (thang) { 6. case 1: 7. case 3: 8. case 5: 9. case 7: 10 case 8: 11. case 10: 12. case 12:{ 13. ngay=31; 14. break; } 15. case 4: 16. case 6: 17. case 9: 18. case 11:{ 19. ngay=30; 20 break; } 21 case 2:{
22. if((nam%400==0)||((nam%4==0)&&(nam%100!=0))){ 23 ngay=29;
24. }else {
25. ngay=28; }
26. break; }}} 27. return ngay ; }}
Hình 3.16. Mã nguồn hàm songayhs_1 của học sinh thứ nhất
Hình 3.17. Mã nguồn hàm songayhs_2 của học sinh thứ hai
public int songayhs_2(intthang, intnam) {
intngay=0; swiTch (thang) { case 1: case 3: case 5: case 7: case 8: case 10: case12:{ ngay=31; break; } case 4: case 6: case 9: case11:{ ngay=30; break; } case2:{
if((nam%400==0)||((nam%4==0)&&(nam%100!=0))){
ngay=29;
}else {
ngay=28; }
break; } }
returnngay ;}}
public int songayhs_1(intthang, intnam) { 1. int ngay=0;
2. if(((thang<0)||(thang>12))||(nam<0)||(nam>9999)){ 3. return -1; 4. }else { 5. switch (thang) { 6 case 1: 7. case 3: 8. case 5: 9. case 7: 10. case 8: 11. case 10: 12. case12:{ 13. ngay=31; 14. break; } 15. case 4: 16. case 6: 17. case 9: 18. case11:{ 19. ngay=30; 20. break; } 21. case 2: ngay=28; 22. break; } } 23. return ngay ;}}
Sau khi thực hiện kiểm thử trên bài tập của hai học sinh, kết quả được ghi lại trong Bảng 3.6. Với mỗi hàm, chúng ta thực hiện 19 ca kiểm thử như ở Hình 3.15. Trên mã nguồn của học sinh thứ nhất phát hiện hai ca kiểm thử lỗi (xảy ra ở các ca kiểm thử số 4 và số 5). Trên mã nguồn của học sinh thứ hai, phát hiện ba ca kiểm thử (xảy ra ở ca kiểm thử thứ 1, thứ 17 và thứ 19)
Bảng 3.6. Kết quả kiểm thử bài tập tính số ngày trong thángcủa hai học sinh
Hàm kiểm thử Số Test Số lỗi phát hiện
songay_1(int thang, int nam) 19 2
songay_2(int thang, int nam) 19 3 Kiểm thử giá trị biên cho hàm songay
Ta tiếp tục phân tích hàm songay để sinh các ca kiểm thử giá trị biên. Hàm nhận hai biến đầu vào là thang có miền xác định [1,12] và nam có miền xác định là [0,9999]. Với biến thang, ta chọn các giá trị biên và cận biên để thực hiện kiểm thử là 0, 1, 2, 11, 12, 13 và một giá trị ở giữa là 6 dại diện cho giá trị thông thường của
thang. Với biến nam, ta chọn các giá trị biên và cận biên để thực hiện kiểm thử là -1, 0, 1, 9998, 9999, 10000 và một giá trị ở giữa là 5000 đại diện cho giá trị thông thường của nam.
Đầu ra của hàm là hai giá trị thang, nam thỏa mãn các biểu thức điều kiện trên mã nguồn. Các ca kiểm thử thỏa mãn nhánh case kiểm tra các tháng 1 và từ tháng 3 đến tháng 12 đã được sinh bởi công cụ nên ta không thực hiện lại. Ta quan tâm đến biểu thức điều kiện case kiểm tra tháng 2 của hàm. Tại dòng 22, biến đầu ra của hàm là giá trị year thỏa mãn biểu thức(year%400==0)||((year%4==0) &&(year%100!=0). Toán tử liên kết giữa biểu thức (year%400==0) và ((year%4==0)&&(year%100!=0) là toán tử "||" nên câu lệnh 22 đúng khi một trong hai biểu thức là đúng. Ta chọn giá trị biên để kiểm thử cho biểu thức (year %400==0) là year=2000, các giá trị cận biên là 1999 và 2001. Với biểu thức
((year%4==0)&&(year%100!=0)), ta chọn giá trị kiểm thử là year = 1996 làm giá trị biên, các giá trị cận biên là 1995, 1997. Bảng 3.7 mô tả các ca kiểm thử giá trị biên cho hàm songay. Các dữ liệu kiểm thử sẽ được sử dụng để kiểm thử giá trị biên cho các bài tập của học sinh.
Kết quả kiểm thử giá trị biên trên hai bài tập của học sinh được ghi lại trong Bảng 3.8. Với mã nguồn của của học sinh thứ nhất, phát hiện được bảy ca kiểm thử lỗi trên biên. Trên mã nguồn của học sinh thứ hai, phát hiện được mười ba ca kiểm thử lỗi trên biên. So với các ca kiểm thử sinh ra từ công cụ, bộ ca kiểm thử giá trị biên đã giúp phát hiện thêm các lỗi xảy ra trên các bài làm của học sinh.
Bảng 3.7. Các ca kiểm thử giá trị biên cho hàm songay
Bảng 3.8. Kết quả kiểm thử giá trị biên bài tập tính số ngày trong tháng của hai học sinh
Hàm kiểm thử Số ca kiểm thử biên Số lỗi phát hiện
songay_1(int thang, int nam) 55 7
songay_2 (int thang, int nam) 55 33
STT Input EO RO STT Input EO
thang Nam Thang nam
1 0 -1 -1 29 11 -1 -1 2 0 0 -1 30 11 0 30 3 0 1 -1 31 11 1 30 4 0 500 -1 32 11 500 30 5 0 9998 -1 33 11 9998 30 6 0 9999 -1 34 11 9999 30 7 0 100000 -1 35 11 100000 -1 8 1 -1 -1 36 12 -1 -1 9 1 0 31 37 12 0 31 10 1 1 31 38 12 1 31 11 1 500 31 39 12 500 31 12 1 9998 31 40 12 9998 31 13 1 9999 31 41 12 9999 31 14 1 100000 -1 42 12 10000 -1 15 2 -1 -1 43 13 -1 -1 16 2 0 0 44 13 0 -1 17 2 1 19 45 13 1 -1 18 2 500 0 46 13 500 -1 19 2 9998 0 47 13 9998 -1 20 2 9999 0 48 13 9999 -1 21 2 100000 -1 49 13 10000 -1 22 6 -1 -1 50 2 1995 28 23 6 0 31 51 2 1996 29 24 6 1 31 52 2 1997 28 25 6 500 31 53 2 1999 28 26 6 9998 31 54 2 2000 29 27 6 9999 31 55 2 2001 28 28 6 100000 -1
Bài toán 3: Tìm ước số chung lớn nhất
Hình 3.18 là mã nguồn chuẩn của hàm timuscln mà ta dùng để sinh các ca kiểm thử cho bài toán tìm ước số chung lớn nhất của hai số nguyên. Hàm nhận giá trị đầu vào là hai số nguyên x và y, đầu ra là ước số chung lớn nhất của x và y.
Hình 3.18. Mã nguồn chuẩn của hàm timuscln
Ta sử dụng công cụ, để sinh ca kiểm thử với độ phủ cao nhất của hàm timuscln. Sinh ca kiểm thử phủ điều kiện con, kết quả cho ta sáu ca kiểm thử được mô tả trong Hình 3.19.
Hình 3.19. Chi tiết các ca kiểm thử cho tiêu chí phủ nhánh của hàm timuscln
Trên mã nguồn, ngoài các câu lệnh rẽ nhánh bên ngoài và tại vòng lặp while,
thân vòng lặp while cũng chứa câu lệnh rẽ nhánh, chia đường đi qua vòng lặp while
thành hai vòng lặp đơn. Khi chúng ta bấm vào thẻ "tất cả các nhánh", công cụ sinh các ca kiểm thử đi qua tất cả các nhánh trên CFG, được mô tả ở Hình 3.20. Với tám ca kiểm thử được sinh ra như ở Hình 3.20, đã đạt được độ phủ cao nhất cho mã nguồn. Ta sẽ sử dụng các ca kiểm thử này để kiểm thử trên bài tập của học sinh ở Hình 3.21 và 3.22.
public int timuscln(intx, inty) { 1. if(x<0) 2. x=-x; 3. if(y<0) 4. y=-y; 5. if(x==0) 6. return x; 7. if(y==0) 8. return y; 9. while(x!=y) { 10. if(x>y) 11. x=x-y; else 12. y=y-x; 13. return x; }}
Hình 3.20. Chi tiết các ca kiểm thử phủ tất cả các nhánh của hàm timuscln
Hình 3. 21. Mã nguồn hàm timuscnl_1 của học sinh thứ nhất
Hình 3.22. Mã nguồn hàm timuscln_2 của học sinh thứ hai
Kết quả kiểm thử trên hai bài tập của học sinh được ghi lại trong Bảng 3.9. Số ca kiểm thử cần thực hiện với mỗi hàm là tám ca như Hình 3.20. Với hàm timuscln_1, phát hiện được hai ca kiểm thử lỗi (xảy ra ở ca kiểm thử số 4). Với hàm timuscln_2, phát hiện được hai ca kiểm thử lỗi (xảy ra ở ca kiểm thử số 6 và số 7).
public int timuscln_2(int x, int y) { if(x<0) x=-x; if(x==0) return x; if(y==0) return y; while(x!=y) { if(x>y) { x=x-y; }else y=y-x;} return x; }
public int timuscln_1(int x, int y) { if(x<0) x=-x; if(y<0) y=-y; while(x!=y) { if(x>y) { x=x-y; }else y=y-x;} return x; }}
Bảng 3.9. Kết quả kiểm thử bài tập tìm ƣớc số chung lớn nhất của hai học sinh
Hàm kiểm thử Số Test Số lỗi phát hiện
timuscln_1(int x, int y) 8 1
timuscln_2(int x, int y) 8 2
Các ca kiểm thử sinh ra ở Hình 3.20 mới chỉ đạt được độ phủ trên tất cả các nhánh của đồ thị. Tuy nhiên lại không kiểm tra được các lỗi xảy ra ở giá trị biên và vòng lặp. Khi thực hiện hai ca kiểm thử với bộ dữ liệu đầu vào là (1, 0) và (0, 1) cho hàm timuscln_1 thì cả hai ca kiểm thử này đều lỗi, trong khi tám ca kiểm thử được sinh ra ở Hình 3.20 không có ca kiểm thử nào có bộ giá trị đầu vào là (0, 1). Rõ ràng, bộ ca kiểm thử sinh ra chưa đủ để phát hiện các lỗi trên mã nguồn. Chúng ta cần phân tích tiếp mã nguồn để sinh các ca kiểm thử cho giá trị biên và vòng lặp cho hàm
timuscln.
Kiểm thử giá trị biên cho hàm timuscln
Ta thực hiện phân tích giá trị biên để sinh thêm các ca kiểm thử cho hàm
timuscln, các ca kiểm thử biên được mô tả như ở Bảng 3.10. Hàm timuscln nhận giá trị đầu vào là hai biến x và y kiểu nguyên có miền xác định là tất cả các số âm và số dương nên ta không có giá trị cận biên cho hai biến đầu vào. Đầu ra của hàm là các cặp (x,y) thỏa mãn các biểu thức điều kiện ở câu lệnh rẽ nhánh trên mã nguồn.
Ta sẽ đánh dấu "-" tại các ca kiểm thử biên trùng với các ca kiểm thử sinh ra từ công cụ ở cột "Ghi chú" của Bảng 3.10 để không phải thực hiện lại các ca kiểm thử đó. Với biểu thức điều kiện trên câu lệnh 1 (x<0, y bất kỳ), ta cần thực hiện ba ca kiểm thử với giá trị (x<0, y<0); (x<0; y=0); (x<0; y>0). Giả sử ta thực hiện ca kiểm thử với dữ liệu kiểm thử là cặp giá trị (-1, -1); (-1,0); (-1; 1).
Tương tự, ở biểu thức điều kiện trên câu lệnh 3 (y<0, x bất kỳ), ca kiểm thử với cặp giá trị (x<0, y<0) đã trùng với ca kiểm thử khi phân tích biểu thức câu lệnh 1 nên ta chỉ sinh các ca kiểm thử ứng với cặp (x=0; y<0); (x>0, y<0). Giả sử ta thực hiện ba ca kiểm với dữ liệu kiểm thử là cặp giá trị (0, -1), (1, -1)
Ở biểu thức điều kiện trên câu lệnh 5 (x=0, y bất kỳ), các ca kiểm thử ứng với căp giá trị (x=0, y<0) đã trùng với ca kiểm thử khi phân tích câu lệnh 3, nên ta chỉ sinh ca kiểm thử với hặp (x=0, y=0); (x=0; y>0). Giả sử ta thực hiện hai ca kiểm thử với dữ liệu kiểm thử là (0,0) và (0,1);
Tương tự, ở biểu thức điều kiện trên câu lệnh 7 (x bất kỳ, y = 0), các ca kiểm thử ứng với cặp giá trị (x = 0, y = 0) và (x < 0,y = 0) đã trùng với ca kiểm thử trước, nên ta chỉ cần sinh ca kiểm thử với (x > 0, y = 0).
Ở biểu thức điều kiện trên câu lệnh while (x!=y), ta sinh hai ca kiểm thử với thỏa mãn điều kiện (x=y) và (x!=y). Ca kiểm thử x=y đã được sinh ra ở ca kiểm thử (x=0, y=0). Ca kiểm thử thỏa mãn điều kiện x!=y đã được sinh ra ở các ca kiểm thử trước nên ta không thực hiện lại. Ta sẽ xét cách kiểm thử vòng lặp while theo quy trình kiểm một quy trình riêng.
Bảng 3.10. Các ca kiểm thử giá trị biên cho hàm timuscln
STT Input EO RO Ghi chú x y 1 -1 -1 1 2 -1 0 0 3 -1 1 1 4 0 -1 0 5 1 -1 1 6 0 0 0 - 7 0 1 0 8 1 0 0 -
Như vậy, bằng cách phân tích mã nguồn để thêm các ca kiểm thử giá trị biên, (một số ca kiểm thử đã trùng với các ca kiểm thử sinh ra từ công cụ), thì kiểm thử biên cho ta thêm sáu ca kiểm thử mà công cụ chưa sinh được ra. Kết quả kiểm thử giá trị biên lên hai bài tập của học sinh được ghi lại ở Bảng 3.11. Trên bài tập của học sinh thứ nhất, phát hiện hai lỗi (xảy ra ở ca kiểm thử biên thứ 1 và thứ 4). Với bài tập của học sinh 2, phát hiện được một lỗi (ứng với ca kiểm thử biên thứ 1).
Bảng 3.11. Kết quả kiểm thử giá trị biên bài tập tìm uscln của hai của học sinh
Hàm kiểm thử Số Test Số lỗi phát hiện
timuscln_1(int x, int y) 6 2
timuscln_2(int x, int y) 6 1
Kiểm thử vòng lặp while cho hàm timuscln
Các ca kiểm thử được sinh ra trong Hình 3.20 và giá trị biên ở Bảng 3.9 mới chỉ đảm bảo phủ toàn bộ các nhánh và biên trên mã nguồn. Tuy nhiên, đường kiểm thử đi qua vòng lặp while của hàm chỉ được thực hiện một lần, khó mà phát hiện được các lỗi khi vòng lặp while thực hiện một số lần lặp nhất định. Để giải quyết vấn đề này, chúng ta cần sinh thêm các ca kiểm thử cho vòng lặp while. Trong hàm timuscln, chúng ta không biết trước số lần lặp của vòng lặp while, do đó chúng ta sẽ thực hiện các ca TIEU LUAN MOI download : skknchat@gmail.com
kiểm thử để vòng lặp while thực hiện lặp 0 lần, một lần, hai lần, và một số k bất kỳ (k>2) lần lặp. Các ca kiểm thử ứng với số lần lặp 0 lần và 1 lần đã được công cụ sinh ra ở ca kiểm thử số 1 và số 2 trên Hình 3.20 . Nên ta chỉ cần thực hiện kiểm thử vòng lặp while với 2 trường hợp là 2 lần lặp và 4 lần lặp như trên Bảng 3.12.
Bảng 3.12. Các ca kiểm thử vòng lặp cho hàm timuscln
Áp dụng các ca kiểm thử vòng lặp while lên bài tập của hai học sinh, kết quả kiểm thử được ghi lại trong Bảng 3.13.
Bảng 3.13. Kết quả kiểm thử vòng lặp while cho hàm tìm uscln của hai học sinh
Hàm kiểm thử Số Test Số lỗi phát hiện
timuscln_1(int x, int y) 2 0
timuscln_2(int x, int y) 2 0
3.6 Ý nghĩa của thực nghiệm
Công cụ sinh ca kiểm thử tự động từ mã nguồn Java là một giải pháp tốt cho bài toán chấm bài lập lập trình của giáo viên. Khi kiểm thử với một mã nguồn chuẩn, công cụ đã sinh ra được các ca kiểm thử mẫu phủ toàn bộ các nhánh trên mã nguồn. Áp dụng các ca kiểm thử mẫu trên bài tập của học sinh bằng các công cụ hỗ trợ kiểm thử (JUnit) đều phát hiện được chính xác các ca kiểm thử lỗi.
Ý nghĩa chính của công cụ sinh ca kiểm thử tự động là thay vì giáo viên phải có kiến thức về kiểm thử mã nguồn và mất nhiều thời gian để thiết kế các ca kiểm thử theo chủ quan của mình, giáo viên chỉ cần cung cấp mã nguồn chuẩn, công cụ sẽ tự động sinh các ca kiểm thử mẫu. Các ca kiểm thử mẫu sẽ là tiêu chí để chấm điểm trên các bài tập của học sinh. Với các ví dụ áp dụng, công cụ đều sinh được các đồ thị và đường đi kiểm thử thỏa mãn các tiêu chí kiểm thử giúp hỗ trợ giáo viên trong việc thiết kế các bài giảng về giải thuật và dễ dàng trao đổi kiến thức một cách trực quan với đồng nghiệp trong các buổi sinh hoạt chuyên môn.
Kết hợp phương pháp sinh ca kiểm thử tự động với phương pháp kiểm thử giá trị biên và vòng lặp, áp dụng trên mã nguồn chuẩn, giáo viên đã có tương đối đầy đủ bộ ca kiểm thử có khả năng phát hiện tất cả các lỗi trên mã nguồn của học sinh. Khi
STT Lặp Input EO RO
1 2 lần (1, 4) 1
2 4 lần (1, 5) 1
chúng ta tự động hóa được quy trình sinh các ca kiểm thử, việc chấm bài tập lập trình cho học sinh sẽ là một công việc dễ thực hiện, nhánh chóng và đạt hiệu quả cao.
So với công cụ đã được nghiên cứu trong [2, 3], phương pháp nghiên cứu có ưu điểm vượt trội là có thể áp dụng vào thực tiễn để hỗ trợ giáo viên trong quá trình chấm bài. Trong khi đó, ở [2] chỉ nghiên cứu phương pháp sinh ca kiểm thử cho ngôn ngữ C và C++ mới ở mức bản mẫu, các ca kiểm thử chỉ sinh ra cho dòng điều khiển chứ chưa