Tìm ước số chung lớn nhất

Một phần của tài liệu (LUẬN văn THẠC sĩ) phương pháp sinh dữ liệu kiểm thử tự động từ mã nguồn và ứng dụng xây dựng hệ thống chấm bài lập trình (Trang 53)

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 xy 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 đề cập đến sinh ca kiểm thử cho vòng lặp và giá trị biên. Phương pháp nghiên cứu trong [3], đã sinh được ca kiểm thử cho mã nguồn Java, nhưng áp dụng cho các chương trình hướng đối tượng. Với các hàm Java hướng cấu trúc như trong đề tài nghiên cứu thì không thực hiện được. Trong [3] cũng chưa đề cập đến việc áp dụng công cụ để hỗ trợ một hệ thống thực tiễn nào.

Chƣơng 4: Kết luận

Luận văn đã tập trung nghiên cứu phương pháp và xây dựng công cụ hỗ trợ việc chấm bài tập lập trình tự động của các học sinh Trung học cơ sở/Trung học phổ thông nhằm giải quyết vấn đề khó khăn của các giáo viên tin học trong việc sinh các ca kiểm thử khi chấm các bài tập. Ý tưởng chính của phương pháp này là sử dụng mã nguồn mẫu (do giáo viên cung cấp) của bài toán để sinh các ca kiểm thử. Quá trình sinh các ca kiểm thử trải qua nhiều công đoạn như: phân tích mã nguồn để sinh đồ thị dòng điều khiển; sinh các đường đi kiểm thử; xác định hệ ràng buộc và tìm nghiệm để sinh dữ liệu kiểm thử tương ứng với mỗi đường đi; và cuối cùng là sinh giá trị đầu ra mong muốn cho từng dữ liệu kiểm thử từ đặc tả của bài toán. Tuy nhiên, các ca kiểm thử sinh ra bởi phương pháp này chưa đủ tốt để phát hiện tất cả các lỗi có thể có của chương trình. Vì vậy, luận văn nghiên cứu các phương pháp sinh các ca kiểm thử cho các vòng lặp (vì lỗi hay xảy ra tại các vòng lặp). Luận văn cũng áp dụng kỹ thuật phân tích giá trị biên để sinh thêm các ca kiểm thử cho giá trị biên và cận biên của các biến. Các ca kiểm thử này sẽ được ghép với các ca kiểm thử sinh ra bằng phương pháp phân tích mã nguồn nhằm kiểm tra tính đúng đắn của các chương trình của học sinh ứng với bài toán đề ra.

Để minh chứng cho kết quả nghiên cứu, luận văn đã tiến hành áp dụng phương pháp này với các chương trình Java. Luận văn cũng đã tiến hành cài đặt công cụ và thử nghiệm với một số chương trình Java đơn giản nhằm minh chứng cho tính đúng đắn và tính hiệu quả của phương pháp nghiên cứu. So với các nghiên cứu trước đây [2, 3] mới chỉ ở dạng bản mẫu, phương pháp đề xuất trong luận văn có tính thực tiễn cao, áp dụng cho hệ thống cho hệ thống chấm bài lập trình tự động, có khả năng ứng dụng trong thực tế. Phương pháp đề xuất trong luận văn có thể sinh được bộ ca kiểm thử tương đối đầy đủ để kiểm tra các lỗi xảy ra trên bài tập của học sinh nhờ việc sinh thêm các ca kiểm thử cho giá trị biên và vòng lặp.

Mặc dù đã có nhiều cố gắng nhưng kết quả của luận văn vẫn tồn tài nhiều hạn chế. Quá trình sinh các ca kiểm thử cho vòng lặp và sinh các ca kiểm thử dựa trên phân tích giá trị biên vẫn chưa tự động hóa được. Công cụ hiện tại mới hỗ trợ các tính năng tối thiểu và chưa được thực nghiệm cẩn thận. Trong thời gian tới, luận văn sẽ tập trung giải quyết các vấn đề nêu trên.

TÀI LIỆU THAM KHẢO

Tiếng Việt

[1] Phạm Ngọc Hùng, Trương Anh Hoàng, Đặng Văn Hưng (2014), Giáo trình kiểm thử phần mềm, NXBĐại học Quốc gia Hà Nội.

[2] Nguyễn Đức Anh (2015), Xây dựng công cụ kiểm thử cho các chương trình C, Khóa luận tốt nghiệp Đại học, Trường Đại học Công nghệ, ĐHQGHN.

[3] Dương Tuấn Anh (2016), Xây dựng công cụ kiểm thử dòng điều khiển tự động cho các đơn vị chương trình Java, Khóa luận tốt nghiệp Đại học, Trường Đại học Công nghệ, ĐHQGHN.

Tiếng Anh

[4] Sangeeta Tanwer and Dharmender Kumar (2010), Automatic tesTcase Generation of C Program Using CFG, IJCSI International Journal of Computer Science Issues, Vol. 7, Issue 4, No 8.

[5] Jurgen Christ, Jochen Hoenicke and Alexander Nutz (2012), SMTInterpol: an Interpolating SMT Solver, Proceeding SPIN'12 Proceedings of the 19th international conference on Model Checking Software, pp.248-254.

[6] Paul C. Jorgensen (2013), Software testing: A craftman's approach, 4th ed., CRC Press, Inc., Boca Raton, FL, USA.

[7] T.J. McCabe (1976), A complexity measure, IEEE Transactions on Software Engineering 2, no. 4, 308-320.

[8] Duc-Anh Nguyen and Pham Ngoc Hung (2017). A Test Data Generation Method for C/C++ Projects. In Proceedings of the Eighth International Symposium on Information and Communication Technology (SoICT 2017). ACM, New York, NY, USA, pp. 431-438.

[9] D. A. Nguyen, P. N. Hung, and V. H. Nguyen (2016). A method for automated unit testing of C programs. In 2016 3rd National Foundation for Science and Technology Development Conference on Information and Computer Science (NICS), pp. 17-22.

[10] David M. Perry , Andrea Mattavelli , Xiangyu Zhang , Cristian Cadar (2017),

Accelerating array constraints in symbolic execution, Proceedings of the 26th ACM SIGSOFT International Symposium on Software Testing and Analysis, pp.10-14.

[11] Ting Su , Geguang Pu , Bin Fang , Jifeng He , Jun Yan , Siyuan Jiang , Jianjun Zhao (2014). Automated Coverage-Driven Test Data Generation Using Dynamic Symbolic Execution, Proceedings of the 2014 Eighth International Conference on Software Security and Reliability, pp. 98-107.

Một phần của tài liệu (LUẬN văn THẠC sĩ) phương pháp sinh dữ liệu kiểm thử tự động từ mã nguồn và ứng dụng xây dựng hệ thống chấm bài lập trình (Trang 53)

Tải bản đầy đủ (PDF)

(60 trang)