Sau đó, đồ thị này được phân tích để thu được một tập các đường thi hành sao cho sau khi thực hiện chúng tiêu chí phủ kiểm thử được thỏa mãn.. Tổng quan về kĩ thuật kiểm thử hộp trắng dò
Trang 1ĐẠI HỌC QUỐC GIA HÀ NỘI TRƯỜNG ĐẠI HỌC CÔNG NGHỆ
KHÓA LUẬN TỐT NGHIỆP ĐẠI HỌC HỆ CHÍNH QUY
Ngành: Công nghệ thông tin
HÀ NỘI - 2016
HÀ NỘI – 2016
Trang 2ĐẠI HỌC QUỐC GIA HÀ NỘI TRƯỜNG ĐẠI HỌC CÔNG NGHỆ
KHÓA LUẬN TỐT NGHIỆP ĐẠI HỌC HỆ CHÍNH QUY
Ngành: Công Nghệ Thông Tin
Trang 3Supervisor: Assoc Prof Dr Pham Ngoc Hung
HANOI - 2016
VIETNAM NATIONAL UNIVERSITY, HANOI UNIVERSITY OF ENGINEERING AND TECHNOLOGY
Trang 4LỜI CẢM ƠN
Đầu tiên, tôi xin gửi lời cám ơn chân thành tới PGS TS Phạm Ngọc Hùng – giảng viên bộ môn Công Nghệ Phần Mềm – người đã hướng dẫn tận tình, tỉ mỉ, chu đáo tôi trong suốt hai năm tham gia nghiên cứu khoa học và làm khóa luận tốt nghiệp Quãng thời gian được thầy hướng dẫn đã giúp tôi học hỏi, đúc kết được nhiều kinh nghiệm về phương pháp nghiên cứu, kĩ năng giao tiếp, kĩ năng làm việc nhóm, kĩ năng trình bày Thầy còn truyền cho tôi ngọn lửa yêu nghiên cứu khoa học, niềm tin vượt qua những khó khăn trong cuộc sống và dạy tôi cách vượt qua những khó khăn đó Tôi cảm thấy tự hào và may mắn khi là một sinh viên được thầy hướng dẫn trong những năm tháng đại học
Ngoài ra, tôi xin gửi lời cám ơn chân thành đến tập thể lớp K57 đã giúp đỡ tôi nhiệt tình để hoàn thành khóa luận sao cho đạt hiệu quả cao nhất Các bạn đã giúp đỡ tôi bằng hành động, bằng lời nói mỗi khi tôi gặp khó khăn, thất bại Bốn năm bên nhau không phải
là dài nhưng đối với tôi, đây là quãng thời gian tuyệt vời nhất và không thể nào quên Tiếp theo, tôi xin gửi lời cảm ơn đến các thầy cô giảng viên Trường Đại học Công Nghệ - Đại học Quốc Gia Hà Nội – những người đã tận tâm truyền đạt những kiến thức quý báu làm nền tảng để tôi tiếp tục đi xa hơn nữa trong lĩnh vực công nghệ thông tin
Cuối cùng, tôi xin được cảm ơn gia đình đã nuôi tôi khôn lớn để trở thành người có ích cho xã hội, giúp tôi có một điểm tựa vững chắc để yên tâm học hành trong suốt bao năm qua Tôi xin gửi lời cám ơn chân thành tới cha, mẹ, em gái đã luôn động viên và cổ vũ tôi mỗi khi tôi gặp khó khăn và thử thách
Hà Nội, ngày 27 tháng 05 năm 2016
Sinh viên
Dương Tuấn Anh
Trang 5TÓM TẮT
Ngôn ngữ lập trình Java vẫn luôn là một trong những ngôn ngữ lập trình phổ biến nhất, có chỗ đứng lâu nhất, bền bỉ và có tầm ảnh hưởng nhất Java được sử dụng trong khoảng 97% máy tính để bàn và có khoảng 1 tỷ bản Java tải về mỗi năm Hơn nữa, Java không đứng yên mà còn phát triển với một phiên bản Java mới là Java 8 đã được phát hành năm ngoái và phiên bản Java 9 dự kiến được phát hành vào năm 2016 Vì sự phổ biến và phát triển không ngừng đó, quá trình kiểm thử trong các dự án Java ngày càng tốn nhiều công sức và chi phí hơn Lượng mã nguồn lớn và phức tạp gây rất nhiều khó khăn trong việc sinh các ca kiểm thử, đặc biệt là trong kĩ thuật kiểm thử hộp trắng Vì vậy, việc tự động hóa quá trình kiểm thử được xem như là một giải pháp để giảm bớt chi phí cho quá trình kiểm thử mà vẫn đảm bảo được chất lượng sản phẩm Hiện nay cũng đã có nhiều công cụ
hỗ trợ kiểm thử tự động cho ngôn ngữ Java nhưng đa số chỉ tập trung vào việc thực thi các
ca kiểm thử mà không chú trọng vào việc sinh ca kiểm thử tự động Một số công cụ hỗ trợ
tự động sinh ca kiểm thử nhưng còn chưa đủ tốt và còn có những hạn chế nhất định
Vì vậy, khóa luận đề xuất một phương pháp sinh ca kiểm thử tự động cho các đơn vị chương trình Java và cài đặt công cụ hỗ trợ CFT4JUnit Phương pháp sử dụng kĩ thuật kiểm thử tự động hộp trắng dòng điều khiển theo hướng tĩnh Đầu vào gồm một hàm Java có chứa các biến số nguyên, số thực, các biến mảng và tiêu chí phủ kiểm thử, số vòng lặp tối
đa Đầu ra gồm tập các ca kiểm thử đáp ứng được tiêu chí phủ kiểm thử và tập các ca kiểm thử cho kiểm thử các vòng lặp Cụ thể, ở bước đầu tiên, đồ thị dòng điều khiển ứng với tiêu chí phủ kiểm thử được xây dựng bằng cách phân tích mã nguồn hàm đầu vào Sau đó, đồ thị này được phân tích để thu được một tập các đường thi hành sao cho sau khi thực hiện chúng tiêu chí phủ kiểm thử được thỏa mãn Tiếp theo, các đường kiểm thử chứa vòng lặp được xử lí để sinh thêm các đường kiểm thử mới dùng kiểm thử tính đúng đắn của vòng lặp Kế tiếp, bằng kĩ thuật thực thi tượng trưng, các đường thi hành sẽ được phân tích thành
hệ ràng buộc tương ứng Cuối cùng, các ca kiểm thử sẽ được thực thi để thu được kết quả kiểm thử Cuối cùng, các ca kiểm thử được sinh ra từ việc giải hệ các ràng buộc Kết quả thực nghiệm cho thấy phương pháp có thể sinh tự động được các ca kiểm thử với số lượng tối thiểu nhưng vẫn đạt được độ phủ tối đa Ngoài ra, khả năng phát hiện lỗi tương đối cao, thời gian sinh các ca kiểm thử cũng được cải thiện đáng kể
Từ khóa: Kiểm thử tự động, hàm Java, đồ thị dòng điều khiển, đường thi hành, ca
kiểm thử, Symbolic Execution, SMT-Solver
Trang 6Therefore, this thesis proposes a method of automated generating test cases for Java unit and install a supporting tool This method use automated testing techniques for white box control flow graph with static direction Inputs include a Java function contains integer variables, real numbers, variables and arrays tested negative criteria, the maximum number
of loops Output consists of a set of test cases to meet the criteria set of government testing and test cases for testing the loop Specifically, in the first step, the control flow graph with specific coverage criteria is built by analyzing the source code input function
Then this graph is analyzed to obtain a set of lines that execution after execution they test negative criteria are met Next, the test contains a loop road is processed to generate additional new tests used road testing the correctness of the loop Next, using symbolic execution techniques, the implementation of the road will be analyzed in the corresponding binding system Then, the test cases are executed in order to obtain test results Finally, the test cases are generated by solving the system of constraints Experimental results show that the method can be automatically generated test cases with the minimum amount but still achieve maximum coverage In addition, the possibility of a relatively high error detection, time of birth of test cases has also improved significantly
Keywords: automatic testing, Java method, control flow graph, test path, test case,
Symbolic Execution, SMT-Solver
Trang 7LỜI CAM ĐOAN
Tôi xin cam đoan rằng những nghiên cứu về kiểm thử tự động cho các đơn vị chương trình Java được trình bày trong luận án này là của tôi và chưa từng được nộp như một báo cáo khóa luận tại trường Đại học Công Nghệ - Đại học Quốc Gia Hà Nội hoặc bất kỳ trường đại học khác Những gì tôi viết ra không sao chép từ các tài liệu, không sử dụng các kết quả của người khác mà không trích dẫn cụ thể
Tôi xin cam đoan công cụ kiểm thử tự động tôi trình bày trong khoá luận là do tôi tự phát triển, không sao chép mã nguồn của người khác Nếu sai tôi hoàn toàn chịu trách nhiệm theo quy định của trường Đại học Công Nghệ - Đại học Quốc Gia Hà Nội
Sinh viên
Trang 8MỤC LỤC
Đặt vấn đề 1
Tổng quan kĩ thuật kiểm thử tự động hộp trắng dòng điều khiển 4
2.1 Tổng quan về kĩ thuật kiểm thử hộp trắng dòng điều khiển 4
2.1.1 Đồ thị dòng điều khiển 4
2.1.2 Các tiêu chí phủ kiểm thử 5
2.1.3 Tự động hóa quy trình kiểm thử hộp trắng dòng điều khiển 6
2.2 Tổng quan về kiểm thử tự động hộp trắng dòng điều khiển theo hướng động 7
2.3 Tổng quan về kiểm thử tự động hộp trắng dòng điều khiển theo hướng tĩnh 8
2.4 So sánh kiểm thử tự động hộp trắng dòng điều khiển theo hướng tĩnh và động 9
Phương pháp sinh ca kiểm thử tự động dòng điều khiển cho các đơn vị của chương trình Java 11
3.1 Tổng quan về phương pháp kiểm thử đề xuất 11
3.2 Sinh đồ thị CFG 12
3.2.1 Tổng quan phương pháp sinh đồ thị CFG 15
3.2.2 Phân tích mã nguồn 16
3.2.3 Phân tích cây AST từ mã nguồn 16
3.2.4 Xây dựng đồ thị dòng điều khiển CFG 18
3.2.4.1 Tổng quan thuật toán sinh đồ thị CFG từ cây AST 18
3.2.4.2 Xử lí các nút đơn giản 20
3.2.4.2 Xử lý nút khối 20
3.2.4.2 Xử lý nút câu lệnh if else 21
3.2.4.2 Xử lý nút câu lệnh for 22
3.2.4.2 Xử lý nút câu lệnh while 23
3.2.4.2 Xử lý nút câu lệnh do…while 24
Trang 93.2.4.2 Xử lý nút câu lệnh đặc biệt 24
3.2.4.2 Liên kết các câu lệnh thực, xóa câu lệnh ảo 25
3.2.5 Chuẩn hóa biểu thức 26
3.3 Xây dựng đường kiểm thử từ đồ thị CFG 27
3.3.1 Sinh tập đường đi độc lập 27
3.3.2 Sinh tập đường kiểm thử cho các tiêu chí phủ 29
3.3.3 Sinh tập đường kiểm thử cho vòng lặp 29
3.3.3.1 Sinh tập đường kiểm thử cho vòng lặp đơn 30
3.3.3.2 Sinh tập đường kiểm thử cho vòng lặp lồng nhau 31
3.4 Sinh ca kiểm thử từ tập đường kiểm thử 32
3.4.1 Xây dựng hệ ràng buộc 32
3.4.2 Sinh ca kiểm thử từ hệ ràng buộc 34
3.4.2.1 Phương pháp giải hệ ràng buộc bằng kĩ thuật sinh giá trị ngẫu nhiên 34
3.4.2.2 Phương pháp giải hệ ràng buộc bằng công cụ SMT-Solver 35
Công cụ và thực nghiệm 38
4.1 Giới thiệu về công cụ 38
4.1.1 Tổng quan về công cụ 38
4.1.2 Đồ thị dòng điều khiển CFG 39
4.1.3 Tập các đường kiểm thử 41
4.1.4 Tập các ca kiểm thử 41
4.1.5 Các thư viện hỗ trợ 42
4.1.5.1 Giới thiệu bộ giải Z3 42
4.1.5.2 Giới thiệu công cụ JDT 42
4.2 Thực nghiệm 43
4.2.1 Kiểm thử hàm đơn giản 43
Trang 104.2.2 Kiểm thử hàm phức tạp 44
4.2.3 Kiểm thử hàm có lỗi tiềm ẩn 45
4.2.4 Ý nghĩa của thực nghiệm 46
Kết luận 47
Trang 11DANH SÁCH KÝ HIỆU, CHỮ VIẾT TẮT
AST Abstract Syntax Tree Cây cấu trúc trừu tượng
JDT Java Development Tooling Thư viện phân tích hỗ phân tích
mã nguồn file Java SMT-
Solver Satisfiability Modulo Theories Solver Bộ giải hệ các phương trình SAT Scholastic Aptitude Test Logic mệnh đề
SE Symbolic Execution Kĩ thuật thực thi tượng trưng
Trang 12DANH SÁCH HÌNH VẼ
Hình 2.1 Các loại đỉnh cơ bản trong đồ thị CFG 5
Hình 2.2 Các cấu trúc điều khiển phổ biến của chương trình 5
Hình 2.3 Quy trình kiểm thử đơn vị chương trình dựa trên độ đo 6
Hình 2.4 Quy trình chung của kiểm thử hộp trắng dòng điều khiển theo hướng động 8
Hình 2.5 Quy trình chung của kiểm thử tự động hộp trắng dòng điều khiển 9
Hình 3.1 Quy trình kiểm thử một hàm java theo phương pháp đề xuất 11
Hình 3.2 Đồ thị CFG của hàm average tiêu chuẩn phủ câu lệnh 14
Hình 3.3 Mã nguồn hàm average 15
Hình 3.4 Tổng quan phương pháp sinh đồ thị CFG từ mã nguồn 15
Hình 3.5 Xử lí nút AST đơn giản 20
Hình 3.6 Xử lí nút AST khối 21
Hình 3.7 Xử lí nút AST lệnh if else 22
Hình 3.8 Xử lí nút AST câu lệnh for 22
Hình 3.9 Xử lý nút AST câu lệnh while 23
Hình 3.10 Xử lý nút AST câu lệnh do while 24
Hình 3.11 Quy trình ghép nối: beforeStm -> R -> END 25
Hình 3.12 Câu lệnh continue: beforeStm -> continueStm 25
Hình 3.13 Câu lệnh break: beforeStm -> breakStm 25
Hình 3.14 Những loại biểu thức được chuẩn hóa 26
Hình 3.15 Quá trình giải hệ ràng buộc bằng kĩ thuật sinh ngẫu nhiên 34
Hình 3.16 Quá trình giải hệ ràng buộc bằng công cụ SMT-Lib 35
Hình 3.17 Cây biểu thức của biểu thức trung tố 2*a + b < c 37
Hình 4.1 Sơ đồ kiến trúc của công cụ CFT4Junit 38
Hình 4.2 Giao diện chính của công cụ 39
Hình 4.3 Đồ thị CFG thỏa mãn tiêu chỉ phủ câu lệnh, phủ nhánh và phủ điều kiện con 40
Trang 13Hình 4.4 Mã nguồn hàm foo 40
Hình 4.5 Tập đường đi thỏa mãn phủ nhánh của hàm foo 41
Hình 4.6 Chi tiết ca kiểm thử ứng với một đường đi trong hàm foo 41
Hình 4.7 Thí dụ về đầu vào và đầu ra của công cụ Z3 42
Hình 4.8 Minh họa cây AST ứng với mã nguồn return x*3 43
Hình 4.9 Mã nguồn hàm min 43
Hình 4.10 Mã nguồn hàm SelectionSort 44
Hình 4.11 Mã nguồn hàm divide 45
Trang 14DANH SÁCH BẢNG
Bảng 4.1 Kết quả kiểm thử hàm min 44
Bảng 4.2 Kết quả kiểm thử hàm SelectionSort 44
Bảng 4.3 Kết quả kiểm thử hàm divide 45
DANH SÁCH THUẬT TOÁN Thuật toán 1 CFG_Generation(f, t) 12
Thuật toán 2 CFG_Generation(AST, t) 19
Thuật toán 3 Path_Generation(CFG) 28
Thuật toán 4 Path_Loop_Generation(path, n) 30
Thuật toán 5 Path_Test_InsideLoop_Generation(path, n) 31
Thuật toán 6 Path_Test_InsideLoop_Generation(path, n) 32
Thuật toán 7 Constraints_Generation(path) 33
Thuật toán 8 Infix_To_Postfix(infixExp) 36
Trang 151
Đặt vấn đề
Ngôn ngữ lập trình Java vẫn luôn là một trong những ngôn ngữ lập trình phổ biến nhất, có chỗ đứng lâu nhất, bền bỉ và có tầm ảnh hưởng nhất Nó đã trở thành một nền tảng thống lĩnh, có mặt tại các ứng dụng trong và ngoài môi trường web, chạy trên tất cả các hệ điều hành nhờ hỗ trợ của cơ chế ảo hóa Java (Java Virtual Machine) bất chấp sự xuất hiện của nhiều ngôn ngữ lập trình mới nổi sau này Java được sử dụng trong khoảng 97% máy tính để bàn và có khoảng 1 tỷ bản Java tải về mỗi năm Hơn nữa, Java không đứng yên mà còn phát triển với một phiên bản Java mới là Java 8 đã được phát hành năm ngoái và phiên bản Java 9 dự kiến được phát hành vào năm 2016 Vì sự phổ biến và phát triển không ngừng
đó, quá trình kiểm thử trong các dự án Java ngày càng tốn nhiều công sức và chi phí hơn Lượng mã nguồn lớn và phức tạp gây rất nhiều khó khăn trong việc sinh các ca kiểm thử, đặc biệt là trong kĩ thuật kiểm thử hộp trắng Vì thế, kiểm thử tự động được xem như là một giải pháp hiệu quả để giải quyết vấn đề này Việc tự động hóa quá trình kiểm thử giúp giảm thiểu thời gian, công sức và chi phí trong khi vẫn đảm bảo độ tin cậy cao của phần mềm Đồng thời, nó còn giúp kiểm thử viên giảm bớt nhàm chán và áp lực trong công việc Ngoài
ra, kiểm thử tự động không chỉ có ý nghĩa khi dự án không đủ tài nguyên mà còn trong kiểm thử hồi quy khi phần mềm cần sửa đổi hoặc nâng cấp
Kiểm thử hộp trắng cho phép phát hiện các lỗi, khiếm quyết tiềm ẩn bên trong chương trình phần mềm[1] Tuy nhiên, để áp dụng các phương pháp kiểm thử hộp trắng, kiểm thử viên không chỉ cần hiểu rõ giải thuật mà còn cần có các kỹ năng và kiến thức tốt về ngôn ngữ lập trình viết mã nguồn, nhằm hiểu rõ mã nguồn cần kiểm thử[1] Hơn nữa, người kiểm thử và người lập trình thường là hai người khác nhau Vì vậy, việc áp dụng các kĩ thuật kiểm thử hộp trắng thường tốn rất nhiều thời gian và công sức, nhất là khi mã nguồn cần kiểm thử có độ phức tạp cao Do đó, các kĩ thuật kiểm thử hộp trắng chủ yếu được sử dụng cho kiểm thử đơn vị
Kĩ thuật kiểm thử hộp trắng có hai phương pháp phổ biến là kiểm thử dòng điều khiển
và kiểm thử dòng dữ liệu Kiểm thử dòng dữ liệu (data flow testing) là kĩ thuật được dùng
để phát hiện lỗi liên quan đến việc khai báo và sử dụng các biến trong chương trình Phương
pháp kiểm thử dòng điều khiển (control flow testing) tập trung kiểm thử tính đúng đắn của
Trang 16kĩ thuật kiểm thử theo hướng động Theo hướng tiếp cận này, mã nguồn sẽ được thực thi với một bộ giá trị đầu vào ngẫu nhiên để đánh dấu một đường thi hành đầu tiên Bằng cách phủ định đường thi hành hiện tại, một đường thi hành mới sẽ được tạo ra Các ràng buộc phân tích từ đường thi hành mới sẽ được giải để sinh được ca kiểm thử tiếp theo Việc kiểm thử hộp trắng dòng điều khiển theo hướng động này còn có một số hạn chế nhất định Thứ nhất, nếu ca kiểm thử đầu tiên không thực thi được thì việc sinh ra các ca kiểm thử tiếp theo
sẽ không thực hiện được Thứ hai, số lượng bộ giá trị kiểm thử có thể rất lớn do việc các đường thi hành có thể bị trùng lặp, hoặc do số lượng các ràng buộc lớn từ việc thực thi các vòng lặp Thứ ba, thời gian sinh ca kiểm thử lâu hơn do mỗi khi sinh một ca kiểm thử, mã nguồn lại phải thực thi một lần Thứ tư, số lượng các ràng buộc sinh ra từ đường thi hành
là rất lớn và phức tạp nên việc giải hệ ràng buộc gặp nhiều khó khăn khi dùng kĩ thuật sinh ngẫu nhiên
Khóa luận này đề xuất một phương pháp sinh ca kiểm thử tự động cho các đơn vị chương trình Java để khắc phục những hạn chế nêu trên Phương pháp sử dụng kĩ thuật kiểm thử hộp trắng dòng điều khiển theo hướng tĩnh Tư tưởng chính của phương pháp là
phân tích mã nguồn để sinh ra đồ thị dòng điều khiển CFG (Control Flow Graph) Các
đường thi hành sẽ được phân tích từ đồ thị CFG Do đó, số lần thực thi mã nguồn được giảm bớt rất nhiều giúp giảm thời gian sinh các ca kiểm thử Hơn nữa, số lượng ca kiểm thử ít hơn mà vẫn đảm bảo được độ phủ tối đa Phương pháp không chỉ kết hợp các thế mạnh của kĩ thuật sinh ngẫu nhiên và công cụ SMT-Solver mà còn đề xuất một kĩ thuật phân loại các ràng buộc để giải Vì thế, phương pháp có thể giải được nhiều loại hệ ràng buộc một cách nhanh hơn
Phần còn lại của khóa luận được trình bày như sau Đầu tiên, chương 2 sẽ giới thiệu tổng quan về kĩ thuật kiểm tự động thử hộp trắng dòng điều khiển Tiếp theo, phương pháp
đề xuất sẽ được trình bày chi tiết trong chương 3 Sau đó, chương 4 sẽ giới thiệu về công
cụ được cài đặt và phát triển dựa trên phương pháp đề xuất cùng với những kết quả thực
Trang 173 nghiệm thu được Cuối cùng, chương 5 trình bày tóm tắt các kết quả đã đạt được, kết luận, những hạn chế và hướng nghiên cứu phát triển trong tương lai
Trang 18là theo hướng tĩnh và hướng động
2.1 Tổng quan về kĩ thuật kiểm thử hộp trắng dòng điều khiển
Kiểm thử hộp trắng dòng điều khiển được sử dụng để kiểm tra tính đúng đắn và phát hiện các lỗi tiềm ẩn trong mã nguồn của dự án phần mềm Đầu vào là mã nguồn của chương trình cùng với tiêu chí phủ kiểm thử Đầu ra sẽ là tập các ca kiểm thử thỏa mãn tiêu chí phủ kiểm thử
2.1.1 Đồ thị dòng điều khiển
Trong kĩ thuật kiểm thử hộp trắng dòng điều khiển, đồ thị dòng điều khiển CFG
(Control Flow Graph) là một phần rất quan trọng Đồ thị này thể hiện một cách tổng quát
và trực quan về các luồng điều khiển trong mã nguồn chương trình Từ đó, người kiểm thử
có thể dễ dàng sinh các ca kiểm thử cho các tiêu chí phủ cũng như đánh giá độ tốt của các
ca kiểm thử Đồ thị CFG của một hàm là một đồ thị có hướng được xây dựng từ mã nguồn của chương trình Đỉnh đầu vào đỉnh cuối đồ thị lần lượt tượng trưng cho trạng thái bắt đầu
và kết thúc của hàm Các đỉnh còn lại, mỗi đỉnh tượng trưng cho một hoặc một nhóm câu
lệnh Nếu câu lệnh tương ứng với đỉnh j được thực hiện ngay sau câu lệnh ứng với đỉnh i thì sẽ tồn tại một cạnh nối từ đỉnh i đến đỉnh j Các cạnh tượng trưng cho dòng điều khiển
giữa các câu lệnh hoặc nhóm câu lệnh
Hình 2.1 mô tả kí hiệu năm loại đỉnh trong đồ thị dòng điều khiển [1] Trong đó:
- Đỉnh bắt đầu, đỉnh kết thúc: Là đỉnh tượng trưng cho trạng thái bắt đầu và kết thúc
của hàm
- Đỉnh xử lí: Là đỉnh tương ứng với các câu lệnh thực thi như câu lệnh gán, câu lệnh
khai báo, khởi tạo, v.v
- Đỉnh quyết định: Là đỉnh tương ứng với các câu lệnh chữa các điều kiện rẽ nhánh như câu lệnh if, do…while, while…do, v.v
Trang 195
- Đỉnh nối: Là đỉnh mà có nhiều hơn một đỉnh khác chỉ đến mà không phải là đỉnh
quyết định
Hình 2.1 Các loại đỉnh cơ bản trong đồ thị CFG
Hình 2.2 mô tả các cấu trúc điều khiển phổ biến của chương trình: tuần tự, if…else,
do…while, while…do, for trong đồ thị dòng điều khiển [1]
Hình 2.2 Các cấu trúc điều khiển phổ biến của chương trình
2.1.2 Các tiêu chí phủ kiểm thử
Khi kiểm thử hộp trắng dòng điều khiển, một trong các đầu vào là tiêu chí phủ kiểm thử Tiêu chí phủ kiểm thử ở đây là một thước đo để đánh giá độ tốt của bộ ca kiểm thử Tập các ca kiểm thử tốt hay không không dựa vào số lượng các ca kiểm thử mà dựa vào độ phủ mà nó đạt được Độ phủ càng lớn thì tập các ca kiểm thử đó càng tốt Độ phủ này được tính bằng tỉ lệ các thành phần kiểm thử được sau khi thực hiện các ca kiểm thử so với tổng
số các thành phần cần kiểm thử của chương trình Các thành phần sẽ được phân chia cụ thể theo từng tiêu chí phủ Trong khóa luận, ba tiêu chí được sử dụng để đánh giá chất lượng
mã nguồn, bao gồm:
- Phủ câu lệnh: Mỗi câu lệnh hay mỗi đỉnh trong đồ thị CFG phải được đi qua thi ít
nhất một lần sau khi thực thi các ca kiểm thử
Đỉnh bắt
đầu Đỉnh xử lí Đỉnh quyết định Đỉnh nối Đỉnh kết thúc
Trang 206
- Phủ nhánh: Các đỉnh quyết định đều được đi qua cả nhánh đúng và nhánh sai sau
khi thực thi các ca kiểm thử
- Phủ điều kiện con: Các đỉnh quyết định đều được đi qua cả nhánh đúng và nhánh
sai, trong đó điểm quyết định có chứa nhiều điều kiện con sẽ được phân tách thành các câu lệnh điều kiện đơn
Quy trình kiểm thử đơn vị chương trình dựa trên các tiêu chí phủ kiểm thử được mô tả như trong Hình 2.3 Đầu tiên, đồ thị dòng điều khiển CFG ứng với mỗi tiêu chí phủ được xây dựng Sau đó, đồ thị này được phân tích để thu được một tập các đường thi hành sao cho sau khi thực hiện chúng tiêu chí phủ kiểm thử được thỏa mãn Tiếp theo, mỗi đường thi hành sẽ được sinh ra một ca kiểm thử tương ứng Cuối cùng, các ca kiểm thử sẽ được thực thi để thu được kết quả kiểm thử
Hình 2.3 Quy trình kiểm thử đơn vị chương trình dựa trên độ đo
2.1.3 Tự động hóa quy trình kiểm thử hộp trắng dòng điều khiển
Hiện nay, lượng mã nguồn lớn và phức tạp gây rất nhiều khó khăn trong việc sinh các
ca kiểm thử, đặc biệt là trong kĩ thuật kiểm thử hộp trắng Vì thế, kiểm thử tự động được xem như là một giải pháp hiệu quả để giải quyết vấn đề này Việc tự động hóa quá trình kiểm thử giúp giảm thiểu thời gian, công sức và chi phí trong khi vẫn đảm bảo độ tin cậy cao của phần mềm Đồng thời, nó còn giúp kiểm thử viên giảm bớt nhàm chán và áp lực trong công việc Ngoài ra, kiểm thử tự động không chỉ có ý nghĩa khi dự án không đủ tài nguyên mà còn trong kiểm thử hồi quy khi phần mềm cần sửa đổi hoặc nâng cấp Nhìn chung, việc tự động hóa quy trình kiểm thử hộp trắng có ba nguyên nhân chính:
- Với một lượng mã nguồn lớn và có độ phức tạp cao thì việc kiểm thử hộp trắng bằng tay khá tốn thời gian, công sức và dễ dẫn đến sai sót Cũng vì lí do đó mà, kiểm thử hộp trắng yêu cầu cao về trình độ chuyên môn và khả năng chịu áp lực của kiểm thử viên
Xây dựng đồ thị luồng điều khiển CFG
Thực thi các
ca kiểm thử
Xác định các đường thi hành
Sinh các ca kiểm thử
Mã nguồn
Tiêu chí
phủ
Trang 217
- Như đã nói ở nguyên nhân trước, kiểm thử hộp trắng yêu cầu kiểm thử viên phải có trình độ chuyên môn sâu rộng về ngôn ngữ cần kiểm thử Vì thế, chi phí tuyển dụng
và đào tạo nguồn nhân lực khá là tốn kém
- Theo như các thống kê thì chi phí dành cho quá trình kiểm thử trong các dự án phần mềm thường chiếm từ 40% đến 60% tổng chi phí Trong khí đó, phần mềm bây giờ thường đòi hỏi yêu cầu cao về chất lượng Hơn nữa, quá trình bảo trì và phát triển phiên bản mới khi được tiến hành sẽ càng làm tăng chi phí kiểm thử
Nhiều phương pháp và công cụ đã được đề xuất để hỗ trợ kiểm thử tự động hộp trắng dòng điều khiển Trong đó, hai phương pháp phổ biến được sử dụng trong kiểm thử tự động dòng điều khiển là theo hướng động vào hướng tĩnh Cả hai kĩ thuật này đều có mục tiêu là sinh các ca kiểm thử để đạt được độ phủ tối đa Mỗi kĩ thuật đều có những điểm mạnh và điểm yếu riêng Kĩ thuật kiểm thử theo hướng tĩnh thích hợp trong việc kiểm thử các mã nguồn dễ phân tích như hàm đơn vị, hàm được viết theo một chuẩn nào đó v.v Trong khi
đó, kĩ thuật kiểm thử theo hướng động phù hợp với các mã nguồn chương trình có độ phức tạp cao, khó phân tích hơn Trong phần tiếp theo, khóa luận sẽ trình bày quy trình chung của từng phương pháp
2.2 Tổng quan về kiểm thử tự động hộp trắng dòng điều khiển theo hướng động
Kĩ thuật kiểm thử tự động hộp trắng dòng điều khiển theo hướng động thường được
sử dụng với những mã nguồn có độ phức tạp cao, khó phân tích Tư tưởng của kĩ thuật là tận dụng thế mạnh của trình biên dịch để phân tích mã nguồn chương trình bằng cách chèn thêm các câu lệnh đánh dấu vào mã nguồn Hình 2.4 mô tả quy trình chung của kĩ thuật này Cụ thể, kĩ thuật gồm các bước sau:
Bước 1 Sinh ngẫu nhiên một bộ giá trị đầu vào hợp lệ
Bước 2 Thực thi chương trình với bộ đầu vào vừa tìm được và đánh dấu đường thi
hành tương ứng
Bước 3 Sinh hệ ràng buộc từ việc phân tích đường thi hành hiện tại
Bước 4 Sinh hệ ràng buộc mới tượng trưng cho đường thi hành tiếp theo bằng cách
phủ định hệ ràng buộc tìm được ở bước 2 Nếu không sinh được hệ ràng buộc mới thì thuật toán kết thúc
Bước 5 Giải hệ ràng buộc thu được ở bước 4 để sinh được bộ giá trị đầu vào mới Nếu
hệ vô nghiệm, quay lại bước 4 Ngược lại, quay lại bước 2
Trang 22Source code Tiêu chí phủ
Sinh bộ đầu vào ngẫu nhiên
Thực thi chương trình
Đánh dấu đường thi hành
Sinh hệ ràng buộc
Tạo đường thi hành mới
Tìm được ca kiểm thử mới
True
False
Kết thúc
Trang 239
Hình 2.5 Quy trình chung của kiểm thử tự động hộp trắng dòng điều khiển
2.4 So sánh kiểm thử tự động hộp trắng dòng điều khiển theo hướng tĩnh và động
Hai kĩ thuật kiểm thử tự động hộp trắng dòng điều khiển theo hướng tĩnh và động đều
có những điểm mạnh vào điểm yếu riêng Chúng có thể hỗ trợ cho nhau để sinh được những
ca kiểm thử tốt nhất Sau đây, khóa luận sẽ đưa ra sự so sánh giữa hai kĩ thuật dựa theo những tiêu chí cụ thể
- Về số ca kiểm thử: Kĩ thuật kiểm thử theo hướng động sẽ phải sinh ra nhiều ca kiểm
thử hơn so với theo hướng tính Trong kĩ thuật kiểm thử theo hướng động, các đường thi hành sẽ được sinh từng cái một từ đường thi hành trước đó nên khả năng trùng lặp giữa các đường thi hành là rất cao Hơn nữa, nếu có sự xuất hiện của vòng lặp,
số lần lặp khi thực thi bộ đầu vào càng nhiều, số lượng các ràng buộc sinh ra từ đường thi hành sẽ càng lớn, dẫn đến số lượng đường thi hành mới có thể được sinh
ra từ đường thi hành này rất là nhiều Nhìn chung, kĩ thuật kiểm thử theo hướng tĩnh
có số lượng đường thi hành và các ca kiểm thử để đạt được độ phủ tối đa là xác định được, còn theo hướng động thì là chưa xác định được cụ thể trước khi kết thúc quá trình kiểm thử
- Về thời gian kiểm thử: Thời gian sinh ca kiểm thử trong kĩ thuật kiểm thử theo hướng
động sẽ lâu hơn so với theo hướng tĩnh Điều đó là do hai lí do Thứ nhất, số lượng
ca kiểm thử cấn sinh ra khi sử dụng kĩ thuật kiểm thử theo hướng tĩnh là lớn hơn,
Mã nguồn Tiêu chí phủ
Xây dựng đồ thị dòng điều khiển
Xây dựng tập đường kiểm thử
Tìm tập ca kiểm
thử Thực thi tập ca kiểm thử
Kết thúc
Trang 2410
trong khi thời gian sinh mỗi ca kiểm thử của cả 2 kĩ thuật là tương đương nhau Thứ hai, với việc kiểm thử theo hướng động, mỗi lần sinh ra ca kiểm thử mới, chương trình sẽ lại phải thực thi thêm một lần
- Khả năng kiểm thử vòng lặp: Kĩ thuật kiểm thử theo hướng tĩnh cho phép chúng ta
có thể kiểm thử từng vòng lặp một trong các vòng lặp lồng nhau với số lần lặp có thể tùy ý Trong khi đó, kĩ thuật kiểm thử theo hướng động chỉ hỗ trợ kiểm thử các vòng lặp một cách đồng thời thay vì riêng rẽ, và số lần lặp là ngẫu nhiên, không xác định theo ý muốn của người kiểm thử
- Tính phức tạp mã nguồn: Hiện nay, các mã nguồn ngày càng phức tạp và được viết
với nhiều quy tắc, phong cách lập trình khác nhau Do đó, việc phân tích mã nguồn trong kĩ thuật kiểm thử theo hướng tĩnh rất là khó khăn và còn có thể không phân tích được Nhưng kĩ thuật kiểm thử theo hướng động hoàn toàn có thể bỏ qua những
sự phức tạp đó Nguyên nhân chính do kiểm thử theo hướng động tận dụng được thế mạnh trình biên dịch để sinh ca kiểm thử mới Kĩ thuật này không làm việc trực tiếp với mã nguồn mà thông qua trình biên dịch nên nó có thể bỏ qua được độ phức tạp
mã nguồn để sinh các ca kiểm thử
Trang 2511
Phương pháp sinh ca kiểm thử tự động dòng điều khiển cho các đơn vị của chương trình Java
3.1 Tổng quan về phương pháp kiểm thử đề xuất
Khóa luận đề xuất một phương pháp sinh ca kiểm thử tự động cho các đơn vị chương trình Java Phương pháp sử dụng kĩ thuật kiểm thử tự động hộp trắng dòng điều khiển theo hướng tĩnh Đầu vào bao gồm một hàm Java có chứa các biến số nguyên, số thực, các biến mảng và tiêu chí phủ kiểm thử, số vòng lặp tối đa Đầu ra là tập các ca kiểm thử đáp ứng được tiêu chí phủ kiểm thử và tập các ca kiểm thử cho kiểm thử các vòng lặp
Hình 3.1 Quy trình kiểm thử một hàm java theo phương pháp đề xuất
Quy trình kiểm thử một hàm đơn vị Java được mô tả chi tiết trong Hình 3.1 Phương pháp gồm những bước chính sau:
Bước 1 Sinh đồ thị dòng điều khiển CFG bằng kĩ thuật phân tích mã nguồn hàm đầu
vào
Trang 2612
Bước 2 Sinh tập các đường đi độc lập từ đồ thị CFG bằng thuật toán duyệt theo chiều
sâu Các đường đi độc lặp là các đường đi từ điểm bắt đầu đến điểm kết thúc của đồ thị dòng điều khiển
Bước 3 Phân tích các đường đi độc lập để thu được tập các đường kiểm thử có thể
đạt được độ phủ thỏa mãn tiêu chí kiểm thử
Bước 4 Các đường kiểm thử có chứa vòng lặp được xử lí để sinh tập đường kiểm
thử cho các vòng lặp
Bước 5 Sử dụng kĩ thuật thực thi tượng trưng SE để sinh được các hệ ràng buộc từ
các đường thi hành Mỗi đường thi hành sẽ có một hệ ràng buộc tương ứng
Bước 6 Giải các hệ ràng buộc để sinh các ca kiểm thử tương ứng Ở bước này, có
hai kĩ thuật phổ biến để giải hệ ràng buộc là SMT-Solver và sinh ngẫu nhiên
Bước 7 Thực thi các ca kiểm thử và đưa ra báo cáo kết quả kiểm thử
3.2 Sinh đồ thị CFG
Thuật toán 1 CFG_Generation(f, t)
Đầu vào: f: một khối các câu lệnh viết bằng ngôn ngữ Java; t:
tiêu chí phủ
Đầu ra: CFG: đồ thị dòng điều khiển của khối lệnh f ứng với độ
phủ t, CFG là biến toàn cục với khởi tạo là đồ thị rỗng
1: s := các khối lệnh con trong khối lệnh đầu vào f 2: for (mỗi câu lệnh con c trong s)
3: if (c là câu lệnh điều khiển) 4: node := đỉnh điều khiển của c
5: Thêm node vào CFG
6: Tạo liên kết giữa node với các đỉnh khác
7: true_node := khối lệnh của nhánh true
Trang 2713
15: CFG_Generation (c, t)
16: else 17: //c là đỉnh thông thường
18: node := đỉnh đại diện cho c
19: Thêm node vào CFG
20: Tạo liên kết giữa node với các đỉnh khác
21: end if 22: end for
Đồ thị CFG là một phần rất quan trọng trong phương pháp kiểm thử tự động hộp trắng dòng điều khiển theo hướng tĩnh Nó biểu diễn mã nguồn một cách chi tiết và trực quan nhất Theo phương pháp này, chúng ta tập trung phân tích và xử lí trên đồ thị CFG để sinh các ca kiểm thử chứ không làm việc trực tiếp với mã nguồn
Chi tiết thuật toán sinh đồ thị dòng điều khiển của hàm Java thỏa mãn một tiêu chuẩn phủ kiểm thử cho trước được trình bày ở Đầu vào thuật toán gồm một khối đoạn mã Java được lưu trong biến f và tiêu chí phủ kiểm thử lưu trong biến t Đầu ra thuật toán là đồ thị dòng điều khiển lưu trong biến CFG Đầu tiên, toàn bộ khối mã nguồn của hàm được truyền vào để xử lý, nó bao gồm một danh sách các câu lệnh bên trong Sau đó, thuật toán duyệt qua từng câu lệnh này và xem xét kiểu của câu lệnh và đưa ra các loại xử lý phù hợp (dòng 2) Đối với các câu lệnh có điều kiện (thí dụ if, for, while, v.v.), điểm điều kiện được đưa vào đồ thị và tạo liên kết (dòng 5, 6) Khi tiêu chí phủ là phủ điều kiện con, điểm điều kiện này sẽ được tách ra thành các điều kiện con trước khi được đưa vào đồ thị Tiếp đó, thuật toán xác định các câu lệnh ứng với nhánh true và false của điều kiện, tiếp tục quá trình xây dựng đồ thị từ các câu lệnh này (dòng 8, 10) Đối với các câu lệnh đặc biệt, thuật toán sẽ xác định đích đến tiếp theo của chúng và liên kết với nhau trong đồ thị (dòng 12, 13) Thí
dụ, câu lệnh return sẽ liên kết tới đỉnh cuối cùng của đồ thị thay vì câu lệnh tiếp theo của
nó trong mã nguồn Đối với câu lệnh thường (thí dụ khởi tạo, gán giá trị, v.v.), đỉnh đại diện cho câu lệnh sẽ được đưa vào đồ thị và liên kết với các câu lệnh khác (dòng 19, 20) Cuối cùng, ta thu được một đồ thị CFG hoàn chỉnh sau khi tất cả các câu lệnh đã được duyệt
Ví dụ cụ thể, Hình 3.2 mô tả đồ thị CFG của hàm average có mã nguồn như Hình 3.3
thỏa mãn tiêu chí phủ nhánh Đầu tiên, mã nguồn sẽ được chia làm bốn phần: câu lệnh khai
báo (dòng 1), khối câu lệnh while (dòng 2 đến 9), khối câu lệnh if (dòng 10, 11) và câu lệnh
Trang 2814
return dòng 12 Với câu lệnh khởi tạo vào câu lệnh return, một đỉnh trên đồ thị CFG được
khởi tạo để đại diện cho chúng Các khối lệnh while và if sẽ tiếp tục được phân chia thành các khối nhỏ hơn Đối với khối câu lệnh while, nó được chia thành hai phần nhỏ hơn nữa
là câu lệnh điều kiện dòng 2 và khối câu lệnh ở phần thân (dòng 3 đến 8) Sau đó, khối câu lệnh từ dòng 3 đến dòng 8 tiếp tục được phân chia thành 4 phần là câu lệnh gán dòng 3,
khối câu lệnh if (dòng 4, 5, 6) và câu lệnh gán dòng 8 Tiếp theo, khối câu lệnh if lại gồm câu lệnh điều kiện (dòng 4), hai câu lệnh gán (dòng 4, 5) Tương tự, khối câu lệnh if ở dòng
10, 11 được chia thành câu lệnh điều kiện (dòng 4) và câu lệnh gán dòng 5 Khi mã nguồn
đã được phân chia đến mức câu lệnh đơn, mỗi câu lệnh đơn được tạo một đỉnh tương ứng trong đồ thị CFG Cuối cùng, sau khi tạo liên kết giữa các đỉnh, một đồ thị CFG của hàm
average ứng với tiêu chí phủ câu lệnh được xây dựng xong
Hình 3.2 Đồ thị CFG của hàm average tiêu chuẩn phủ câu lệnh
Để có thể phân tích được mã nguồn chương trình một cách hiệu quả, thư viện JDT được sử dụng để chuyển đổi hỗ trợ mã nguồn thành định dạng cây cấu trúc trừu tượng
Trang 2915
(Abstract Syntax Tree – AST) Sau đó, một thuật toán được sử dụng để phân tích trên cây AST này và sinh ra đồ thị CFG tương ứng
Hình 3.3 Mã nguồn hàm average
3.2.1 Tổng quan phương pháp sinh đồ thị CFG
Chi tiết quy trình phân tích mã nguồn một hàm viết bằng ngôn ngữ Java để xây dựng
đồ thị dòng điều khiển CFG được trình bày như Hình 3.4 Quy trình thực hiê ̣n gồm ba pha:
Hình 3.4 Tổng quan phương pháp sinh đồ thị CFG từ mã nguồn
Pha 1: Sử du ̣ng JDT (Java Development Tooling) phân tích mã nguồn hàm java để
xây dựng cây cấu trúc trừu tượng AST tương ứng
Pha 2: Xây dựng đồ thị CFG từ cây AST ứng với mã nguồn hàm Java
public double average(int value[], int min, int max){
Xây dựng đồ thị CFG
Chuẩn hóa biểu thức
Mã nguồn hàm Java
Trang 30- Tên của hàm số: chương trình sẽ dùng tên này để tìm kiếm hàm số khi nó được gọi trong thân hàm của một hàm số khác
- Kiểu trả về của hàm số: được dùng để tạo giá trị cụ thể từ một chuỗi string đầu vào
- Danh sách các tham số cần được truyền vào hàm, đây là các biến số cần được tìm giá trị để kiểm tra sự đúng đắn của hàm số
- Phần thân hàm: là một cây cấu trúc AST chứa các câu lệnh cũng như các biểu thức bên trong từng câu lệnh Cấu trúc này được công cụ sử dụng cho việc sinh đồ thị CFG cũng như phục vụ phân tích hệ ràng buộc sau này
3.2.3 Phân tích cây AST từ mã nguồn
Với đầu vào là mã nguồn hàm Java, cây AST tương ứng với đầu vào này được sinh
ra bằng cách sử dụng plugin JDT Plugin này là một phần của IDE Eclipse và có thể chạy
độc lập (stand-alone)
Cấu trúc cây AST của một class Java các thành phần chính sau:
cập (public, private, v.v.), kiểu trả về, khai báo tên và tham số và thân hàm Phần
khai báo gồm có tên hàm và danh sách các khai báo tham số cho hàm Ví dụ: định
nghĩa hàm “public int min(int a, int b){…}” có nhãn giới hạn độ truy cập public,
1 Java Development Tooling: https://eclipse.org/jdt/
Trang 31 Khai báo class: Một khai báo class chứa nhãn giới hạn độ truy cập (public, private,
v.v.) , tên class và phần thân Phần thân class gồm các nút khai báo biến thuộc tính,
các nút định nghĩa hàm
Sau đó, cây AST của hàm cần kiểm thử được xây dựng Cây AST này sẽ được sử dụng để xây dựng đồ thị CFG dưới sự hỗ trợ của các Plugin JDT Hàm cần kiểm thử sẽ được chia thành các câu lệnh/khối câu lệnh, mỗi thành phần được biểu diễn bởi một nút trong cây AST Cấu trúc nút AST của các câu lệnh điển hình bao gồm:
Câu lệnh khởi tạo: Cấu trúc của câu lệnh khởi tạo giống với cấu trúc của khai báo biến toàn cục, bao gồm tên kiểu khai báo và một danh sách các khai báo ứng với từng biến
Câu lệnh gán: Một câu lệnh gán chứa một biểu thức gán bên trong nó Biểu thức
gán là một trường hợp của biểu thức 2 bên (BinaryExpression), gồm 2 biểu thức con và một phép toán ở giữa VD: biểu thử thức x+y gồm hai biểu thức x và y cùng với phép toán +
Câu lệnh khối (được bao bởi cặp dấu ngoặc nhọn “{ }”) bao gồm danh sách các câu lệnh chứa bên trong nó
Câu lệnh if else: Nút câu lệnh if gồm ba thành phần là phần điều kiện, câu lệnh
nhánh đúng và câu lệnh nhánh sai
Câu lệnh for: Nút câu lệnh for bao gồm bốn thành phần: câu lệnh khởi tạo, biểu
thức điều kiện, biểu thức lặp bước, phần thân
Câu lệnh do while: Một nút câu lệnh do while bao gồm phần thân vòng lặp và
phần điều kiện lặp
Các câu lệnh đơn đặc biệt: Các câu lệnh như return, break, continue, v.v