Một cách tổng quát, với mỗi kỹ thuật được dùng trong một giai đoạn kiểm thử động dynamic run-time testing thì bất cứ phần mềm nào cũng có thể được phân ra làm hai công đoạn con: chuẩn bị
Trang 1BỘ GIÁO DỤC VÀ ĐÀO TẠO VIỆN HÀN LÂM KHOA HỌC
VÀ CÔNG NGHỆ VIỆT NAM
HỌC VIỆN KHOA HỌC VÀ CÔNG NGHỆ
-
TÔ HỮU NGUYÊN
MỘT SỐ CẢI TIẾN VỀ RÀNG BUỘC XÂU TRONG SINH DỮ LIỆU KIỂM THỬ TỰ ĐỘNG CHO THỰC THI TƢỢNG
TRƢNG
LUẬN ÁN TIẾN SĨ TOÁN HỌC
Hà Nội - 2020
Trang 2BỘ GIÁO DỤC VÀ ĐÀO TẠO VIỆN HÀN LÂM KHOA HỌC
VÀ CÔNG NGHỆ VIỆT NAM
HỌC VIỆN KHOA HỌC VÀ CÔNG NGHỆ
-
TÔ HỮU NGUYÊN
MỘT SỐ CẢI TIẾN VỀ RÀNG BUỘC XÂU TRONG SINH DỮ LIỆU KIỂM THỬ TỰ ĐỘNG CHO THỰC THI TƢỢNG
TRƢNG
LUẬN ÁN TIẾN SĨ TOÁN HỌC
Chuyên ngành : Cơ sở toán học cho tin học
Trang 3MỤC LỤC
MỤC LỤC i
LỜI CAM ĐOAN iii
LỜI CẢM ƠN iv
DANH MỤC THUẬT NGỮ VÀ TỪ VIẾT TẮT v
DANH MỤC BẢNG BIỂU vi
DANH MỤC HÌNH VẼ vii
MỞ ĐẦU 1
CHƯƠNG 1 TỔNG QUAN VỀ KIỂM THỬ PHẦN MỀM VÀ THỰC THI BIỂU TRƯNG 5
1.1 Kiểm thử phần mềm 5
1.1.1 Các khái niệm cơ bản 5
1.1.2 Các phương pháp kiểm thử 10
1.2 Kỹ thuật kiểm thử hộp trắng dòng điều khiển 12
1.2.1 Kiểm thử hộp trắng dòng điều khiển theo hướng động 12
1.2.2 Kiểm thử hộp trắng dòng điều khiển theo hướng tĩnh 14
1.2.3 Các tiêu chí phủ kiểm thử 15
1.2.4 Đồ thị dòng điều khiển 16
1.2.5 Đường kiểm thử 17
1.3 So sánh kiểm thử hộp trắng dòng điều khiển theo hướng tĩnh và động 17
1.4 Thách thức trong kiểm thử phần mềm 18
1.5 Thực thi biểu trưng 19
1.5.1 Tổng quan về thực thi biểu trưng 19
1.5.2 Thực thi biểu trưng tĩnh 24
1.5.3 Thực thi biểu trưng động 27
1.5.4 Thực thi Concolic 33
1.5.5 Thực thi biểu trưng với các lời gọi phương thức 37
1.6.6 Ràng buộc xâu và vai trò của giải ràng buộc xâu 40
1.6 Kết luận chương 1 42
CHƯƠNG 2 THỰC THI BIỂU TRƯNG VÀ MÔ HÌNH HÓA RÀNG BUỘC 44
2.1 Đặt vấn đề 44
2.1.1 Bùng nổ đường đi 44
Trang 42.1.2 Mô hình hóa bộ nhớ 46
2.2 Thực thi biểu trưng và công cụ mở rộng 47
2.2.1 Thực thi biểu trưng và kiểm thử phần mềm 47
2.2.2 Thực thi biểu trưng trên ngôn ngữ Java 48
2.3 Giải các ràng buộc và thực thi biểu trưng 54
2.4 Ràng buộc hỗn hợp và cải tiến trong giải ràng buộc xâu 56
2.4.1 Đồ thị xâu 58
2.4.2 Xây dựng lại ràng buộc 58
2.4.3 Quá trình tiền xử lý 59
2.4.4 Sinh các ràng buộc xâu và kết quả thực hiện 60
2.4.5 Giải ràng buộc sử dụng Otomat 62
2.5 Kết luận chương 2 62
CHƯƠNG 3 GIẢI RÀNG BUỘC XÂU 63
3.1 Đặt vấn đề 63
3.2 Các vấn đề liên quan đến Bitvector và bộ thỏa mãn SMT (satisfiability modulo theories) 64
3.2.1 Lý thuyết thỏa mãn SMT 64
3.2.2 Giải ràng buộc xâu dựa trên phương pháp BitVector 66
3.3 Giải ràng buộc xâu dựa trên phương pháp sử dụng OTOMAT 67
3.4 Đề xuất giải ràng buộc xâu trong thực thi biểu trưng 70
3.4.1 Mô hình hoá ràng buộc xâu sử dụng đồ thị 71
3.4.2 Phát hiện thêm ràng buộc kiểu nguyên trên dữ liệu xâu 72
3.5 Thực nghiệm và đánh giá kết quả 72
3.6 Kết luận chương 3 85
KẾT LUẬN VÀ KIẾN NGHỊ 86
DANH MỤC CÔNG TRÌNH CỦA TÁC GIẢ 87
TÀI LIỆU THAM KHẢO 88
Trang 5LỜI CAM ĐOAN
Tôi xin cam đoan đây là công trình nghiên cứu của riêng tôi được hoàn thành dưới sự hướng dẫn tận tình của tập thể hướng dẫn gồm
Các kết quả được viết chung với các tác giả khác đã được sự nhất trí của đồng tác giả khi đưa vào luận án Các kết quả nêu trong luận án là trung thực và chưa từng được công bố trong bất kỳ công trình nào trước thời gian công trình của tôi và cộng sự được công bố
Hà Nội, ngày… tháng….năm …
Tác giả luận án
Trang 6
LỜI CẢM ƠN
Trước hết, tác giả xin bày tỏ lòng biết ơn chân thành và sâu sắc tới các thầy giáo hướng dẫn, TS Nguyễn Trường Thắng và PGS TS Đặng Văn Đức Sự tận tình giúp đỡ, chỉ bảo, động viện tận tình và quí báu mà các thầy đã dành cho tác giả trong suốt quá trình thực hiện luận án là không thể nào kể hết được
Xin chân thành cảm ơn các thầy các cô, các nhà khoa học thuộc Viện Công nghệ thông tin và Học viện khoa học và Công nghệ đã tận tình giúp đỡ và tạo một môi trường làm việc hết sức thuận lợi giúp tác giả thực hiện tốt công việc nghiên cứu của mình
Xin chân thành cảm ơn Ban Giám Hiệu Trường đại học Công nghệ thông tin
và Truyền thông – Đại học Thái Nguyên đã hết sức tạo điều kiện về thời gian và công việc để tác giả có thể tập trung hoàn thành quá trình học tập, nghiên cứu của mình Đặc biệt xin gửi lời cảm ơn đến các thầy cô, các bạn đồng nghiệp trong Khoa Công nghệ thông tin đã động viên, giúp đỡ tác giả trong suốt quá trình nghiên cứu
Cuối cùng, xin gửi lời cảm ơn sâu sắc nhất tới gia đình, bạn bè và người thân, những người đã luôn là nguồn động viên để tác giả có thể học tập và nghiên cứu, luôn sẻ chia những khó khăn vất vả trong quá trình nghiên cứu và hoàn thiện
đề tài
Hà Nội, ngày… tháng….năm …
Tác giả luận án
Trang 7
DANH MỤC THUẬT NGỮ VÀ TỪ VIẾT TẮT
MJI Model Java Interface
DFA Deterministic Finite Automaton
PC Điều kiện đường dẫn (path condition)
QTKT Quy trình kiểm thử
SAT Boolean satisfiability problem
SDLC Software Development Life Cycle
SE Thực thi biểu trưng (Symbolic Execution)
SET Cây thực thi biểu trưng (Symbolic Execution Tree) SMT Satisfiability Modulo Theories
SQA Software quality assurance
STLC Software Test Life Cycle
UT Kiểm thử đơn vị - Unit Testing
VSUnit Visual Studio Unit Testing
Trang 8DANH MỤC BẢNG BIỂU
Bảng 1.1 Ví dụ về thực thi biểu trưng động 29
Bảng 1.2 So sánh thực thi Concolic với thực thi biểu trưng 34
Bảng 1.3 Minh họa việc chuyển đổi từ mã nguồn Java sang mã Jimple 35
Bảng 1.4 Mô tả ràng buộc xâu 41
Bảng 2.1 Xây dựng các ràng buộc cho các phép toán trên xâu 61
Bảng 3.1 Xây dựng ràng buộc tương ứng với các phép toán trên xâu 66
Bảng 3.2 Kết quả đánh giá mô hình cải tiến trên bộ dữ liệu 79
Trang 9DANH MỤC HÌNH VẼ
Hình 1.1 Mối quan hệ giữa phát triển phần mềm và kiểm thử phần mềm 9
Hình 1.2 Quy trình chung của kiểm thử hộp trắng theo hướng động 13
Hình 1.3 Ví dụ về chèn mã nguồn trong DMS/SRT 14
Hình 1.4 Mã nguồn hàm triangle sau khi thêm mã nguồn 14
Hình 1.5 Quy trình chung của kiểm thử hộp trắng theo hướng tĩnh 15
Hình 1.6 Các cấu trúc điều khiển phổ biến 17
Hình 1.7 Ví dụ về ý tưởng thực hiện cụ thể của thực thi biểu trưng 23
Hình 1.8 Cây thực thi biểu trưng 26
Hình 1.9 Thực thi biểu trưng với phương thức nhận đầu vào là đối tượng 31
Hình 1.10 Cây thực thi biểu trưng được quản lý riêng 33
Hình 1.11 Thực thi biểu trưng trên lời gọi phương thức 38
Hình 2.1 Mô hình hoạt động của JPF 49
Hình 2.2 Sơ đồ trạng thái trong quá trình kiểm thử 50
Hình 2.3 Biểu diễn sơ đồ kiến trúc mức cao của JPF 51
Hình 2.4 Ví dụ về trừu tượng hoá dữ liệu 52
Hình 2.5 Một ví dụ khác về trừu tượng hoá dữ liệu 52
Hình 2.6 Quy trình sàng lọc dữ liệu 53
Hình 2.7 Đồ thị xâu 57
Hình 2.8 Thuật toán giải ràng buộc hỗn hợp 58
Hình 2.9 Đồ thị sau khi loại bỏ phép toán equals 60
Hình 2.10 Các ràng buộc không thỏa mãn sau khi loại bỏ phép toán equals 60
Hình 2.11 Các đỉnh mới đại diện cho độ dài xâu được bổ sung 61
Hình 3.1 Giải ràng buộc xâu dựa trên Otomat 69
Hình 3.2 Phương thức giải ràng buộc phủ định 70
Hình 3.3 Sơ đồ mô hình hoá ràng buộc xâu sử dụng đồ thị 71
Hình 3.4: Thuật toán giải ràng buộc xâu 73
Hình 3.5 Chương trình Java kiểm thử 75
Hình 3.6 Kết quả sinh dữ liệu biểu trưng trên một số phép toán trên xâu 76
Hình 3.7 Code kiểm thử 78
Trang 10Hình 3.8 Kết quả đánh giá mô hình cải tiến trên bộ dữ liệu 80
Hình 3.9 Chương trình Java 81
Hình 3.10 Đồ thị xâu 1 82
Hình 3.11 Đồ thị xâu 2 83
Trang 11MỞ ĐẦU
Kiểm thử phần mềm (testing) là một trong những hoạt động quan trọng nhất trong chu trình phát triển phần mềm Theo số liệu thống kê thực tế, kiểm thử phần mềm chiếm tới 50-60% tổng chi phí toàn bộ quy trình phát triển phần mềm Để giảm chi phí kiểm thử và tăng mức độ tin cậy của phần mềm, các nhà nghiên cứu đang cố gắng tự động hoá các hoạt động phục vụ công việc kiểm thử phần mềm [1, 2]
Một cách tổng quát, với mỗi kỹ thuật được dùng trong một giai đoạn kiểm thử động (dynamic run-time testing) thì bất cứ phần mềm nào cũng có thể được phân ra làm hai công đoạn con: chuẩn bị các ca kiểm thử (test case) cho việc kiểm tra phần
mềm và thực hiện chạy chương trình cần kiểm thử trên một nền tảng hỗ trợ các nghiệp
vụ kiểm thử (testing framework) với các ca kiểm thử đã có
Công việc đầu tiên và hết sức quan trọng đó là chuẩn bị bộ dữ liệu kiểm thử Việc này thường được làm thủ công nên cần rất nhiều nhân lực để tạo ra bộ dữ liệu đầy đủ, có tính bao phủ cao (coverage criteria) trên toàn bộ các đường tính toán (computation paths) của chương trình Các ca kiểm thử bao gồm dữ liệu kiểm thử và các giá trị đầu ra mong muốn
Một trong các hoạt động quan trọng để giảm chi phí kiểm thử phần mềm là sinh các ca kiểm thử một cách tự động và có tính đầy đủ Các tổ chức phát triển phần mềm thường phải chi phí một lượng lớn về tài chính cho các hoạt động liên quan đến kiểm thử phần mềm Tính hiệu quả của tiến trình xác minh và thẩm định phụ thuộc nhiều vào số lỗi được tìm ra và được sửa chữa trước khi sản phẩm được chuyển giao Điều này đồng nghĩa với quan điểm chất lượng của phần mềm phụ thuộc chặt chẽ vào chất lượng các ca kiểm thử được sinh ra
Trong những năm qua, nhiều nghiên cứu của các nhà khoa học trên thế giới nhằm ―sinh dữ liệu kiểm thử một cách tự động‖ [3, 4] để giảm thiểu chi phí cho phần mềm Có hai cách tiếp cận căn bản để sinh dữ liệu kiểm thử đó là dựa vào mã nguồn (code) và dựa vào mô hình (model) Đối với phương pháp dựa vào mã nguồn là phương pháp cho khả năng bao phủ cao, có khả năng loại bỏ các dòng lệnh không cần thiết chứa các tiềm ẩn gây lỗi nhưng cần thiết phải có khả năng tối ưu tính toán của các phần mềm phân tích kiểm thử, do vậy gần đây có nhiều nghiên cứu tập trung vào phương pháp này [5, 6, 7]
Trang 12Trong những năm qua, nhiều nghiên cứu về việc sinh các ca kiểm thử một cách
tự động như: sinh các ca kiểm thử dựa vào đặc tả, sinh các ca kiểm thử dựa vào mô hình, sinh ca kiểm thử hướng đường dẫn và kỹ thuật thông minh Tuy nhiên, kiểm thử dựa vào thực thi biểu trưng đã và đang là hướng nghiên cứu được nhiều người quan tâm
Các kỹ thuật cơ bản sinh dữ liệu kiểm thử tự động mà các nhà nghiên cứu đã đề xuất đó là: Dựa vào chứng minh định lý (test case generation by theorem proving) [8, 9]; Dựa vào thực thi biểu trưng (test case generation by symbolic execution [5, 7, 10-12]); Dựa vào kiểm chứng mô hình (test case generation by model checking) [13]; Dựa vào một mô hình luồng sự kiện (test case generation by an event-flow model [14]); Dựa vào việc sử dụng mô hình xích Markov (test case generation by using a
Markov chains model) [15]
Trong đó kỹ thuật thực thi biểu trưng (symbolic execution) đang là vấn đề được nhiều nhà khoa học trên thế giới tìm hiểu, phát triển và xây dựng các ứng dụng [5, 6, 7] Hiện nay kỹ thuật này đã và đang được phát triển trên nhiều công cụ, nhiều ngôn ngữ như: C/C++, JavaScrip, Net, java, HTML vv Trong phạm vi giới hạn nghiên cứu, nội dung của luận án tập trung nghiên cứu về một số cải tiến trong bộ giải ràng buộc xâu áp dụng sinh các ca kiểm thử Các cài đặt thực nghiệm và đánh giá được thực hiện bằng ngôn ngữ Java do Java là ngôn ngữ mạnh mẽ, hiện đại Hơn nữa, Java đang được sử dụng rộng rãi với các thư viện trên kiểu dữ liệu xâu đa dạng, phong phú
và được sử dụng trong nhiều dự án lớn trong hiện tại và tương lai
Mục tiêu nghiên cứu của luận án:
Nghiên cứu các phương pháp mô hình hóa ràng buộc giải ràng buộc từ đó cải tiến khả năng giải ràng buộc và áp dụng kỹ thuật thực thi biểu trưng trong tự động sinh các ca kiểm thử Cài đặt thử nghiệm các phương pháp đề xuất trong sinh tự động các ca kiểm thử trên kiểu dữ liệu xâu và kiểu dữ liệu hỗn hợp Phân tích, đánh giá kết quả sau khi thử nghiệm
Đối tượng và phạm vi nghiên cứu:
Tổng quan về các phương pháp tự động sinh các ca kiểm thử phần mềm, kỹ thuật thực thi biểu trưng và ứng dụng trong sinh tự động các ca kiểm thử Các kỹ thuật
mô hình hóa ràng buộc, giải ràng buộc trên các kiểu dữ liệu dựa trên hai phương pháp Otomata và Bitvector, Nghiên cứu, phân tích đánh giá các phương pháp hiện có sinh
Trang 13ca kiểm thử trên các kiểu dữ liệu khác nhau Đánh giá hiệu quả, chất lượng của các ca kiểm thử được tạo ra so với thực tế chương trình
Nội dung nghiên cứu:
Các phương pháp kỹ thuật sinh tự động cá ca kiểm thử, các vấn đề liên quan
mô hình hóa ràng buộc trên các kiểu dữ liệu Nghiên cứu cải tiến mô hình hóa và giải ràng buộc trên kiểu dữ liệu xâu kí tự, từ đó ứng dụng trong kỹ thuật thực thi biểu trưng thực hiện sinh các ca kiểm thử tự động trên kiểu xâu kí tự cho các chương trình kiểm thử
Phương pháp nghiên cứu:
Nghiên cứu, phân tích, tổng hợp các liệu liên quan đến thực thi biểu trưng, vai trò của giải ràng buộc cũng như giải ràng buộc triên kiểu dữ liệu xâu trong thực thi biểu trưng trong sinh tự động các ca kiểm thử (các bài báo, tạp chí, trên mạng Internet ) Cải tiến mô hình hóa ràng buộc và nâng cao khả năng giải ràng buộc trên kiểu dữ liệu xâu và ràng buộc hỗn hợp, phân tích, đánh giá các kết quả đã công bố
Các đóng góp của luận án:
Xây dựng mô hình hóa ràng buộc trên kiểu dữ liệu xâu và ràng buộc hỗn hợp, cải tiến khả năng giải ràng buộc trong phương pháp thực thi biểu trưng Cài đặt kỹ thuật mô hình hóa và giải ràng buộc dựa trên Otomat và Bitvector trong giải ràng buộc xâu, đánh giá so sánh các kết quả thu được với các các kết quả đã công bố
Bố cục của luận án:
Cấu trúc luận án bao gồm phần mở đầu, ba chương nội dung, phần kết luận,
danh mục công trình công bố và danh mục các tài liệu tham khảo Nội dung chính của các chương trong luận án như sau:
Chương 1 của luận án trình bày tổng quan về kiểm thử phần mềm và kỹ thuật thực thi biểu trưng ứng dụng trong tự động sinh các ca kiểm thử Đồng thời trình bày các lý thuyết cơ sở sử dụng trong luận án nhằm đưa ra cái nhìn tổng quan về bài toán nghiên cứu, về sử dụng kỹ thuật thực thi biểu trưng ứng dụng trong sinh tự động các
ca kiểm thử và hướng nghiên cứu cụ thể của luận án
Chương 2 của luận án trình bày kết quả nghiên cứu về các phương pháp mô hình hóa ràng buộc, giải ràng buộc trong thực thi biểu trưng Áp dụng các công cụ này vào các trường hợp cụ thể cùng với các đánh giá tính hiệu quả của các phương pháp này trên kiểu dữ liệu cụ thể
Trang 14Chương 3 của luận án trình bày các kết quả nghiên cứu của các cải tiến mô hình hóa ràng buộc trên kiểu xâu và ràng buộc hỗn hợp, giải ràng buộc trong thực thi biểu trưng trên kiểu dữ liệu xâu và dữ liệu hỗn hợp Đồng thời trình bày việc mở rộng kỹ thuật thực thi biểu trưng, cách thực hiện giải ràng buộc xâu dựa trên phương pháp Otomat
Phần kết luận nêu những đóng góp, hướng phát triển, những vấn đề quan tâm; danh mục các công trình đã được công bố của luận án và danh sách các tài liệu tham khảo được sử dụng trong luận án cũng được trình bày
Trang 15CHƯƠNG 1 TỔNG QUAN VỀ KIỂM THỬ PHẦN MỀM VÀ THỰC THI BIỂU
TRƯNG
Chương này trình bày lý thuyết tổng quan về kiểm thử và sinh dữ liệu kiểm thử, thực thi biểu trưng và ứng dụng của thực thi biểu trưng trong sinh các ca kiểm thử Trong đó, trình bày các khái niệm cơ bản và các phân tích liên quan đến kỹ thuật thực thi biểu trưng Đồng thời, một vài thách thức và hướng phát triển của luận án cũng được trình bày trong chương này
1.1 Kiểm thử phần mềm
1.1.1 Các khái niệm cơ bản
Để đảm bảo một hệ thống phần mềm hoặc các thành phần của phần mềm làm việc như mong muốn là một thách thức lớn trong ngành công nghiệp phần mềm Các phần mềm lỗi gây ra những tổn thất về kinh tế cũng như những hậu quả nghiêm trọng khác tùy thuộc vào lĩnh vực mà phần mềm được sử dụng Do đó cần phải phát hiện và khắc phục các lỗi của phần mềm trước khi sử dụng Có các phương pháp khác nhau để phát hiện lỗi của phần mềm bao gồm kiểm chứng mô hình (model checking) [16], các
kỹ thuật phân tích tĩnh (static analysis) [17] và kiểm thử (software testing) [18 - 23]
Trong kiểm chứng mô hình, một mô hình của hệ thống được tạo ra để hỗ trợ phân tích mọi sự thực thi có thể trong mô hình Kiểm chứng mô hình có thể kiểm chứng được rằng mô hình của hệ thống hoạt động chính xác trong tất cả trường hợp có thể Hạn chế của kiểm chứng mô hình đó là không gian trạng thái của mô hình thường quá lớn do đó việc khám phá tất cả các trạng thái không phải lúc nào cũng thực hiện được Trong khi đó, các kỹ thuật phân tích chương trình tĩnh thường đưa ra nhiều cảnh báo (warnings) không tương ứng với các lỗi thực sự Các kỹ thuật kiểm thử phát hiện
ra các lỗi thực sự nhưng thường không phát hiện ra được tất cả các lỗi do chỉ phân tích một số sự thực thi trong chương trình
Kiểm thử phần mềm là quá trình thực thi một chương trình với mục đích tìm ra
lỗi Kiểm thử phần mềm đảm bảo sản phẩm phần mềm đáp ứng chính xác, đầy đủ và đúng theo yêu cầu của khách hàng, yêu cầu của sản phẩm đã đặt ra Kiểm thử phần mềm cũng cung cấp mục tiêu, cái nhìn độc lập về phần mềm, điều này cho phép việc đánh giá và hiểu rõ các rủi ro khi thực thi phần mềm
Kiểm thử phần mềm là một phần trong tiến trình bảo đảm chất lượng phần mềm (Software Quality Assurance -SQA) Trong SQA, phần mềm chuyên xử lý và kiểm
Trang 16toán viên được quan tâm đến quá trình phát triển phần mềm hơn là chỉ các hiện vật như tài liệu, mã số và hệ thống Họ kiểm tra và thay đổi phần mềm quy trình kỹ thuật riêng của mình để giảm số lượng các lỗi mà kết thúc trong phần mềm được gửi: cái gọi là "tỷ
lệ khiếm khuyết" Chúng tạo nên cái mà một "tỷ lệ lỗi chấp nhận được" phụ thuộc vào bản chất của phần mềm Một chuyến bay mô phỏng trò chơi video sẽ có khả năng chịu lỗi cao hơn nhiều so với phần mềm cho máy bay thực tế Mặc dù có những liên kết chặt chẽ với SQA, các phòng kiểm thử thường tồn tại một cách độc lập, và có thể không có chức năng SQA trong một số công ty
Kiểm thử phần mềm được hiểu là quá trình phát hiện lỗi trong phần mềm bằng cách đối chiếu kết quả kỳ vọng từ một chương trình máy tính với kết quả thực tế của
nó cho một tập hợp các yếu tố đầu vào Ngược lại, bảo đảm chất lượng là việc thực hiện các chính sách và thủ tục nhằm ngăn ngừa khiếm khuyết xảy ra trong chương trình
Kế hoạch kiểm thử (Test plan)
Kế hoạch kiểm thử chính là tài liệu tổng quan về việc kiểm thử một dự án bao gồm: phạm vi kiểm thử, hướng tiếp cận, quy trình kiểm thử (QTKT), tài nguyên và nhân lực kiểm thử cần có, các chức năng/mô đun cần được kiểm thử, các công cụ và môi trường kiểm thử cần có Kế hoạch kiểm thử bao gồm cả kế hoạch ai kiểm thử chức năng nào, khi nào bắt đầu thực hiện viết và hoàn thành ca kiểm thử, khi nào bắt đầu thực hiện kiểm thử và kế hoạch hoàn thành kiểm thử Dựa vào kế hoạch chung của dự án để lên kế hoạch cho bên kiểm thử Trong trường hợp khi làm thực tế thấy có khả năng không đúng như kế hoạch đã lên thì phải báo cáo lại trưởng nhóm kiểm thử hoặc quản trị dự án sớm
Trang 17Mục tiêu thiết kế ca kiểm thử là tìm ra nhiều lỗi nhất với chi phí và thời gian ít nhất Trong các thập kỷ 80-90 của thế kỷ XX, người ta đã nghiên cứu nhiều loại phương pháp thiết kế ca kiểm thử
Câu hỏi đặt ra là khi nào thì kiểm thử xong? Làm thế nào để biết rằng kiểm thử
đã đủ? Về nguyên tắc là không bao giờ kiểm thử được tất cả đồng thời vận hành chương trình là đang kiểm thử và kiểm thử tiếp tục khi chương trình còn hoạt động Kỹ
sư phần mềm cần các tiêu chuẩn nghiêm ngặt để xác định có cần phải tiếp tục kiểm thử không
Thiết kế ca kiểm thử trong kiểm thử phần mềm là quá trình xây dựng các phương pháp kiểm thử có thể phát hiện lỗi, sai sót, khuyết điểm của phần mềm để xây dựng phần mềm đạt tiêu chuẩn Thiết kế ca kiểm thử giữ vai trò quan trọng trong việc nâng cao chất lượng phần mềm bởi bước thiết kế ca kiểm thử Mục đích thiết kế ca kiểm thử nhằm tạo ra các ca kiểm thử tốt nhất có khả năng phát hiện ra lỗi, sai sót của phần mềm một cách nhiều nhất và tạo ra các ca kiểm thử có chi phí rẻ nhất, đồng thời tốn ít thời gian và công sức nhất
Một trong những yêu cầu quan trọng nhất trong kiểm thử chương trình là thiết
kế và tạo ra các ca kiểm thử có hiệu quả Với những ràng buộc về thời gian và chi phí
đã cho, thì vấn đề then chốt của kiểm thử trở thành xác định tập con nào của tất cả ca kiểm thử có thể có khả năng tìm ra nhiều lỗi nhất
Thông thường, phương pháp kém hiệu quả nhất là kiểm tra tất cả đầu vào ngẫu nhiên – quá trình kiểm thử một chương trình bằng việc chọn ngẫu nhiên một tập con các giá trị đầu vào có thể Về mặt khả năng tìm ra nhiều lỗi nhất, tập hợp các ca kiểm thử được chọn ngẫu nhiên có rất ít cơ hội là tập hợp tối ưu hay gần tối ưu Sau đây là một số phương pháp để chọn ra một tập dữ liệu kiểm thử một cách thông minh
Để kiểm thử hộp đen và kiểm thử hộp trắng một cách thấu đáo là không thể
Do đó, một chiến lược kiểm thử hợp lý là chiến lược có thể kết hợp sức mạnh của cả hai phương pháp trên Nghĩa là phát triển một cuộc kiểm thử nghiêm ngặt vừa bằng việc sử dụng các phương pháp thiết kế ca kiểm thử hướng hộp đen nào đó và sau đó
bổ sung thêm những ca kiểm thử này bằng việc khảo sát tính logic của chương trình,
sử dụng phương pháp hộp trắng
Trang 18Do kiểm thử thường là khâu cuối cùng trong quá trình phát triển phần mềm (trước khi phần mềm được phân phối đến người sử dụng) nên cũng có thể đặt câu hỏi tương đương ―Khi nào thì kết thúc việc kiểm thử và phân phối sản phẩm?‖
Có nhiều câu trả lời khác nhau cho những câu hỏi trên, mỗi câu trả lời hướng tới những kĩ thuật và hành động khác nhau Khi không có một sự đánh giá chuẩn thì quyết định dừng kiểm thử sản phẩm phần mềm dựa trên hai yếu tố chính, một là Tài nguyên: Quyết định có tiếp tục quá trình kiểm thử hay không dựa trên sự tiêu tốn tài nguyên, hai tiêu chuẩn trạng thái để dừng kiểm thử là ―Vượt quá thời gian và tiêu tốn quá nhiều tiền‖ Hai là quyết định dừng kiểm thử khi đã hoàn thành tất cả các hoạt động kiểm thử theo như kế hoạch kiểm thử đã đề ra
Đối với những giai đoạn đầu của quá trình kiểm thử hay các tiêu chuẩn kết thúc kiểm thử, liên quan tới các hành động kiểm thử cục bộ, những tiêu chuẩn tin cậy dựa trên những kịch bản sử dụng của khách hàng và tần suất sử dụng có thể không còn ý nghĩa nhiều Ví dụ, trong một số hệ thống phần mềm, một số thành phần không bao giờ được sử dụng trực tiếp bởi người sử dụng và một số thành phần thì có tần suất sử dụng rất thấp Do vậy việc lựa chọn các tiêu chuẩn khác là cần thiết Những tiêu chuẩn mới này là các tiêu chuẩn bao phủ, nó bao hàm các tiêu chuẩn khác nhau, định nghĩa các kĩ thuật dùng trong tình huống kiểm thử và các thành phần khác có liên quan Các
kĩ thuật kiểm thử hướng tới các tiêu chuẩn này được gọi là các kĩ thuật kiểm thử hướng bao phủ
Ngoài các ràng buộc về tài nguyên và giới hạn của con người, có hai loại tiêu chuẩn để kết thúc hành động kiểm thử Tiêu chuẩn thứ nhất dựa trên thống kê sử dụng của người dùng để xác định các thành phần cũng như các yếu tố liên quan để kiểm thử, còn được gọi là kiểm thử thống kê hướng sử dụng Tiêu chuẩn thứ hai bao gồm các tiêu chuẩn về mọi vấn đề liên quan tới kiểm thử đơn vị, xét tới mọi khả năng gây lỗi của chương trình (kết thúc kiểm thử) có các kĩ thuật kiểm thử hướng bao phủ
Vai trò của kiểm thử trong phát triển phần mềm, bảo trì và vận hành:
Kiểm thử nghiêm ngặt hệ thống và tài liệu có thể giúp giảm thiểu những vấn đề rủi ro xảy ra trong quá trình vận hành và góp phần nâng cao chất lượng của hệ thống phần mềm, nếu như các lỗi được tìm thấy và sửa chữa trước khi hệ thống được vận hành thực tế
Trang 19Kiểm thử và chất lượng: Kiểm thử mang lại sự tự tin về chất lượng của phần mềm nếu
nó tìm thấy một vài lỗi hoặc không tìm thấy lỗi Kiểm thử đúng sẽ giảm thiểu được tổng thể mức độ rủi ro của hệ thống Khi quá trình kiểm thử tìm thấy lỗi, chất lượng
của hệ thống phần mềm được nâng cao sau khi những lỗi đó được sửa chữa
Kiểm thử bao nhiêu là đủ:
Việc quyết định kiểm thử bao nhiêu là đủ phụ thuộc vào mức độ của rủi ro bao gồm kỹ thuật, độ an toàn, rủi ro trong kinh doanh và hạn mức của dự án như là thời gian và ngân sách Kiểm thử nên cung cấp đủ thông tin để các bên liên quan có thể quyết định về việc bàn giao phần mềm hoặc hệ thống đã qua kiểm thử cho các bước phát triển tiếp theo hay bàn giao cho khách hàng
Kiểm thử chính là kỹ thuật được sử dụng phổ biến nhất để phát hiện và khắc phục các lỗi của phần mềm nhằm đảm bảo chất lượng của phần mềm Chi phí dành cho việc kiểm thử chiếm khoảng 50% tổng chi phí trong phát triển phần mềm Kiểm thử là một tiến trình quan trọng trong kỹ nghệ phần mềm Kiểm thử đơn vị chính là bước đầu tiên trong quá trình kiểm thử đó
Hình 1.1 Mối quan hệ giữa phát triển phần mềm và kiểm thử phần mềm
Trong hình 1.1, phía bên trái của mô hình là vòng đời phát triển phần mềm - SDLC (Software Development Life Cycle), phía bên phải của mô hình là vòng đời kiểm thử Phần mềm - STLC (Software Test Life Cycle) và toàn bộ nội dung được thể hiện dưới dạng chữ V, do đó mô hình này được gọi là Mô hình chữ V (V - model)
Ngoài mô hình chữ V, còn có các mô hình phát triển lặp, trong đó việc phát triển được thực hiện theo từng giai đoạn, với mỗi giai đoạn sẽ phát triển thêm một chức năng
Trang 20cho phần mềm Mỗi giai đoạn bao gồm các hoạt động xây dựng và kiểm thử độc lập nhau
1.1.2 Các phương pháp kiểm thử
Các kỹ thuật kiểm thử phổ biến [24] bao gồm:
Kiểm thử hộp đen (Black box testing)
Kiểm thử hộp đen là một phương pháp kiểm thử mà người kiểm thử sẽ chỉ xem xét đến đầu vào và đầu ra của chương trình mà không quan tâm mã nguồn bên trong được viết ra sao Kỹ thuật viên kiểm thử thực hiện kiểm thử dựa hoàn toàn vào đặc tả yêu cầu Mục đích của kiểm thử hộp đen là tìm ra các lỗi ở giao diện, chức năng của phần mềm
Kiểm thử hộp trắng (White box testing)
Kiểm thử hộp trắng là phương pháp kiểm thử mà cấu trúc thuật toán của chương trình được đưa vào xem xét Các ca kiểm thử được thiết kế dựa vào cấu trúc mã hoặc cách làm việc của chương trình Người kiểm thử truy cập vào mã nguồn của chương trình để kiểm tra nó
Các mức độ kiểm thử:
Kiểm thử đơn vị (Unit test)
Kiểm thử đơn vị là hoạt động kiểm thử nhỏ nhất Kiểm thử thực hiện trên các hàm hay thành phần riêng lẻ Đây là công việc mà để thực hiện được nó thì người kiểm thử sẽ phải hiểu biết về mã nguồn, về chương trình và các hàm Thông thường lập trình viên sẽ làm nó trước khi giao cho kiểm thử viên Mục đích của việc thực hiện kiểm thử đơn vị là cô lập từng thành phần của chương trình và chứng minh rằng các bộ phận riêng lẻ chính xác về các yêu cầu chức năng
Kiểm thử tích hợp (Intergration test)
Một phần mềm được tạo ra sẽ bao gồm rất nhiều mô đun trong đó Để chắc chắn rằng phần mềm hoạt động tốt thì việc gom các mô đun lại với nhau để kiểm tra sự giao tiếp giữa các mô đun cũng như bản thân từng thành phần từng mô đun là hết sức quan trọng Kiểm thử tích hợp bao gồm hai mục tiêu chính là phát hiện lỗi giao tiếp xảy ra giữa các đơn vị khi tích hợp các đơn vị riêng lẻ thành các hệ thống nhỏ và cuối cùng là
1 hệ thống hoàn chỉnh để chuẩn bị cho bước kiểm thử hệ thống
Kiểm thử hệ thống (System test)
Trang 21Kiểm thử một hệ thống đã được tích hợp hoàn chỉnh để xác minh rằng nó đáp ứng được yêu cầu Kiểm thử hệ thống thuộc loại kiểm thử hộp đen Kiểm thử hệ thống tập trung nhiều hơn vào các chức năng của hệ thống Đồng thời, kiểm thử hệ thống cũng thực hiện kiểm tra cả chức năng, giao diện và các hành vi của hệ thống một cách hoàn chỉnh, đáp ứng với yêu cầu
Kiểm thử chấp nhận (Acceptance test)
Trong kiểu kiểm thử này, phần mềm sẽ được thực hiện kiểm tra từ người dùng
để tìm ra nếu phần mềm phù hợp với sự mong đợi của người dùng và thực hiện đúng như mong đợi hay không Trong giai đoạn kiểm thử này, kiểm thử viên có thể cũng thực hiện hoặc khách hàng có các kiểm thử viên của riêng họ để thực hiện Có hai loại kiểm thử chấp nhận đó là kiểm thử Alpha và kiểm thử Beta:
Kiểm thử Alpha: là loại kiểm thử nội bộ Tức là phần mềm sẽ được một đội
kiểm thử độc lập hoặc do khách hàng thực hiện tại nơi sản xuất phần mềm
Kiểm thử Beta: là loại kiểm thử mà khách hàng thực hiện kiểm thử ở chính môi
trường của họ Loại kiểm thử này được thực hiện sau kiểm thử Alpha
Kiểm thử các yêu cầu chức năng (Functional testing)
Kiểm thử chức năng là một loại kiểm thử hộp đen và các ca kiểm thử của nó được dựa trên đặc tả của ứng dụng phần mềm hoặc thành phần đang tiến hành kiểm thử Các chức năng được kiểm thử bằng cách nhập vào các giá trị nhập và kiểm tra kết quả đầu ra, và ít quan tâm đến cấu trúc bên trong của ứng dụng Có thể hiểu một cách đơn giản, kiểm thử chức năng là xác nhận tất cả các chức năng của hệ thống Nó đánh giá ứng dụng và xác nhận liệu ứng dụng có đang hoạt động theo yêu cầu hay không
Kiểm thử các yêu cầu phi chức năng (Non Functional testing)
Loại kiểm thử này tập trung vào các khía cạnh phi chức năng của ứng dụng Những khía cạnh phi chức năng bao gồm: Kiểm thử chịu tải, Kiểm thử bảo mật, Kiểm tra tính tương thích trên từng môi trường
Kiểm thử cấu hình (Shakeout testing)
Kiểu kiểm thử này cơ bản là kiểu kiểm thử về khả năng của hệ thống mạng, kết nối dữ liệu và sự tương tác của các mô đun Thông thường thì kiểu kiểm thử này là do nhóm quản lý cấu hình chuẩn bị thiết lập các môi trường kiểm thử thực sự Họ cũng kiểm tra xem liệu các thành phần chính của phần mềm có hoạt động bất thường không Kiểu kiểm thử này thực hiện trước khi tiến hành thực hiện trong môi trường kiểm thử
Trang 22Sau khi kiểm thử shakeout, bước kế tiếp là kiểm thử smoke (kiểu kiểm thử được thực hiện bởi tester sau khi biên dịch, được tiến hành trong môi trường kiểm thử)
Kiểm thử hiệu suất (Performance testing)
Trong loại kiểm thử này, ứng dụng được kiểm thử dựa vào sự phức tạp của giá trị, độ dài của đầu vào, độ dài của các câu truy vấn…Loại kiểm thử này kiểm tra bớt phần tải (stress/load) của ứng dụng có thể được chắc chắn hơn
Kiểm thử hồi quy (Regression testing)
Kiểm thử hồi quy là kiểm thử lại một chức năng đã được xây dựng xong, đã được kiểm thử xong, đã hết lỗi nhưng do có sự sửa đổi một chức năng khác mà lại có ảnh hưởng đến nó Khi phải kiểm thử một chức năng đã xong rồi thì gọi là kiểm thử hồi quy
1.2 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 chia ra gồm kiểm thử hướng tĩnh và kiểm thử hướng động Đầu vào của hai kĩ thuật này đều là mã nguồn và tiêu chí phủ kiểm thử Sau một loạt quá trình phân tích, đầu ra tương ứng là tập ca kiểm thử Mỗi một kĩ thuật đều có những ưu điểm và hạn chế riêng Mục tiêu của kiểm thử hộp trắng dòng điều khiển là tìm tập ca kiểm thử tối thiểu nhưng đạt được độ phủ tối đa
1.2.1 Kiểm thử hộp trắng dòng điều khiển theo hướng động
Theo kĩ thuật này, mã nguồn sẽ được thêm các đoạn chương trình con trước khi thực thi trong môi trường chạy Hình 1.2 trình bày quy trình chung của kiểm thử động Nhìn chung, kĩ thuật này gồm sáu bước cơ bản được diễn giải theo thứ tự dưới đây:
Bước 1 Chèn thêm các đoạn mã nguồn mới vào mã nguồn cần kiểm thử Bước 2 Chọn ngẫu nhiên một tập giá trị đầu vào hợp lệ làm ca kiểm thử đầu tiên Bước 3 Thực thi chương trình với bộ giá trị vừa tìm được Nếu không thực thi
được, quay lại bước 2 để sinh bộ giá trị khác
Bước 4 Tìm tập các câu lệnh đã được đi qua với bộ giá trị ở bước 3 để xây
dựng được hệ ràng buộc tương ứng
Bước 5 Phủ định hệ ràng buộc thu được ở bước 4 để sinh các hệ ràng buộc
mới có tác dụng sinh các ca kiểm thử kế tiếp Nếu không thể sinh hệ phủ định nào khác, thuật toán kết thúc
Bước 6 Giải hệ ràng buộc thu được ở bước 5 để sinh ca kiểm thử kế tiếp Nếu
không có ca kiểm thử nào thỏa mãn, quay về bước 5 để tìm hệ ràng buộc phủ định
Trang 23mới sao cho khác hệ ràng buộc hiện tại Ngược lại, quay lại bước 3 để sinh ca kiểm thử kế tiếp
Hình 1.2 Quy trình chung của kiểm thử hộp trắng theo hướng động
Trong bước 1, quá trình chèn thêm khối mã nguồn mới vào mã nguồn cần kiểm thử được tiến hành một cách tự động Công cụ DMS/SRT 5 được đánh giá khá mạnh
mẽ để thực hiện pha này Đoạn mã nguồn thêm vào có chức năng đánh dấu, thoát chương trình hoặc ghi thông tin về quá trình thực thi ra tệp, v.v Để làm được điều này, chúng ta cần xây dựng các luật chèn thêm mã nguồn mới vào mã nguồn cần kiểm thử
Với công cụ DMS/SRT, mỗi một luật bắt đầu với từ khóa rule và theo sau là tên đặt cho luật Từ khóa rewrite to nêu cách biến đổi đoạn mã nguồn gốc về đoạn mã nguồn mới Kiểu dữ liệu có thể là expression (ứng với biểu thức), statement (ứng với câu lệnh gán hoặc khởi tạo), type (ứng với kiểu dữ liệu), identifier (ứng với định danh như tên biến, tên hàm), v.v Hình 1.3 mô tả một luật chèn thêm câu lệnh đánh dấu vào khối lệnh điều khiển rẽ nhánh
Pha chèn thêm khối lệnh mới
Tìm được ca kiểm thử mới
Kết thúc
Tìm ca kiểm thử khởi đầu ngẫu nhiên
Thực thi ca kiểm thử vừa tìm được Tái tạo đường thực thi
Tạo đường thực thi
mới
Source Tiêu chí
Trang 24Hình 1.3 Ví dụ về chèn mã nguồn trong DMS/SRT
Cụ thể, biến mảng visited đánh dấu vị trí câu lệnh đi qua được bổ sung vào mã nguồn ban đầu ngay sau mỗi khối lệnh điều khiển rẽ nhánh Hình 1.4 đưa ra mã nguồn triangle sau khi áp dụng luật
Hình 1.4 Mã nguồn hàm triangle sau khi thêm mã nguồn
1.2.2 Kiểm thử hộp trắng dòng điều khiển theo hướng tĩnh
Trong kiểm thử tĩnh, mã nguồn không được thực thi trong môi trường chạy để sinh ca kiểm thử Trong kiểm thử tĩnh, quá trình chạy ca kiểm thử chỉ thực hiện duy nhất một lần với từng ca kiểm thử để tính toán giá trị trả về và đảm bảo ca kiểm thử
Trang 25thực thi không có vấn đề Các bước tổng quát trong kĩ thuật này được trình bày ở Hình 1.5 Đầu tiên, đồ thị dòng điều khiển được xây dựng dựa trên mã nguồn và tiêu chí phủ kiểm thử Bước tiếp theo, từ đồ thị dòng điều khiển chúng ta xây dựng được tập đường kiểm thử Mỗi một đường kiểm thử trong tập đường kiểm thử mô tả hành vi chương trình với một miền bộ đầu vào nào đó Sau đó, pha tìm kiếm ca kiểm thử thỏa mãn đường kiểm thử được tiến hành Cuối cùng, ca kiểm thử được thực thi trong môi trường chạy
Hình 1.5 Quy trình chung của kiểm thử hộp trắng theo hướng tĩnh
1.2.3 Các tiêu chí phủ kiểm thử
Tiêu chí phủ kiểm thử là một thước đo để đánh giá tính đúng đắn của mã nguồn cần kiểm thử với một tập ca kiểm thử nào đó Tập ca kiểm thử khiến mã nguồn có độ phủ cao được đánh giá là tốt hơn so với tập ca kiểm thử khác khiến mã nguồn có độ phủ thấp hơn Chất lượng mã nguồn được đánh giá tỉ lệ thuận với độ phủ
Độ phủ được đánh giá dựa trên hai thông số gồm tiêu chí phủ kiểm thử và tập
ca kiểm thử Công thức tính độ phủ là tỉ lệ các thành phần được kiểm thử trên tổng số các thành phần cần kiểm thử sau khi đã thực hiện tập ca kiểm thử Thành phần có thể là câu lệnh, điểm quyết định, điều kiện con, đường thi hành hoặc là sự kết hợp của chúng
Tiêu chí phủ kiểm thử được giới thiệu lần đầu tiên vào 1963 trong tạp chí hàng tháng ―Communications of the ACM‖ Cho tới nay, nhiều tiêu chí phủ kiểm thử được đưa ra Luận án sử dụng ba tiêu chí phủ kiểm thử phổ biến để đánh giá chất lượng mã nguồn gồm:
Trang 26 Phủ câu lệnh: Mỗi một câu lệnh được thực thi ít nhất một lần sau khi chạy tập
đầu tiên của hàm, đỉnh cuối cùng của CFG là trạng thái kết thúc của hàm Đỉnh i nối đến đỉnh j thì câu lệnh tương ứng đỉnh j có thể được thực thi sau khi thực hiện câu lệnh tương ứng ở đỉnh i
Trong ngôn ngữ C, các cấu trúc điều khiển trong CFG gồm tuần tự, rẽ nhánh, while do, do while, for Hình 1.6 minh họa các cấu trúc điều khiển nêu trên Trong
đó đỉnh có nhãn c biểu trưng cho câu lệnh điều kiện Các đỉnh còn lại tượng trưng câu
lệnh gán, khai báo, v.v Các thành phần cơ bản của đồ thị dòng điều khiển gồm đỉnh xuất phát, đỉnh xử lí, đỉnh quyết định, đỉnh kết nối và đỉnh kết thúc Trong đó:
Đỉnh xuất phát và đỉnh kết thúc: Hai đỉnh này là duy nhất, trong đó đỉnh xuất phát đại diện cho tên hàm
Đỉnh quyết định: Là đỉnh tương ứng với câu lệnh điều kiện trong khối lệnh điều khiển rẽ nhánh, do while, while do Ví dụ cụ thể, với khối lệnh điều khiển ―if (a b) { }‖ thì đỉnh quyết định tương ứng với ―a > b‖
Đỉnh kết nối: Là đỉnh có nhiều hơn hai đỉnh khác trỏ đến mà không phải đỉnh quyết định
Đỉnh xử lí: Là đỉnh tương ứng với câu lệnh gán, câu lệnh khởi tạo hoặc câu lệnh khai báo và không phải đỉnh kết nối Các khối lệnh điều khiển cũng chứa các loại
câu lệnh này Ví dụ, khối lệnh ―for (i = 0; i < 10; i++)‖ chứa hai đỉnh xử lí gồm câu lệnh gán ―i = 0‖ và câu lệnh tăng giá trị biến i là ―i++‖
Trang 27Tuần tự if…else do….while while….do for
Hình 1.6 Các cấu trúc điều khiển phổ biến
1.2.5 Đường kiểm thử
Với một bộ giá trị đầu vào, một tập các câu lệnh gán, câu lệnh khai báo và câu lệnh điều kiện được đi qua Danh sách các câu lệnh này được sắp theo thứ tự thực hiện chính là một đường đi Trong số tất cả các đường đi có thể, một tập đường đi được chọn sao cho thỏa mãn tiêu chí phủ kiểm thử được gọi là tập đường kiểm thử
Đường kiểm thử là một đường đi từ đỉnh đầu tiên đến đỉnh cuối cùng của CFG được biểu diễn dưới một tập các đỉnh từ đỉnh v1đến đỉnh vn, trong đó hai đỉnh liền kề
có cạnh nối với nhau Nếu cạnh (vi, vj ) (i≠ j) là nhánh false, câu lệnh lưu ở đỉnh v i được
viết phủ định Tập đường đi độc lập gồm k đường đi PATH1, PATH2, …, PATHk thỏa mãn: giữa mọi cặp đường đi độc lập PATHi và PATHj (i ≠ j) không có ít có cạnh chung
Tìm kiếm tập đường kiểm thử là bước trung gian trong quá trình sinh tập ca kiểm thử
1.3 So sánh kiểm thử hộp trắng dòng điều khiển theo hướng tĩnh và động
Mỗi một kĩ thuật kiểm thử đều có những ưu điểm và hạn chế riêng Để có cái nhìn tổng quan về hai kĩ thuật, luận án đưa ra sự so sánh về số ca kiểm thử, thời gian sinh ca kiểm thử, khả năng kiểm thử vòng lặp, ảnh hưởng bởi phức tạp mã nguồn đối với hai kĩ thuật
Về số ca kiểm thử Nhìn chung, với mã nguồn chỉ chứa các câu lệnh rẽ nhánh
và không chứa vòng lặp, hai kĩ thuật kiểm thử nêu trên cho số bộ ca kiểm thử như nhau Tuy nhiên, trong trường hợp có vòng lặp thì kĩ thuật kiểm thử tĩnh đưa ra số ca kiểm thử ít hơn so với kiểm thử động Theo hướng tĩnh, các đường đi chứa vòng lặp lặp lại một lần sẽ được cấu trúc lại để lặp nhiều hơn một lần Nói cụ thể hơn, từ một
c
c
c
c
Trang 28đường kiểm thử chứa vòng lặp ban đầu sẽ sinh ra một tập các đường kiểm thử mới dùng để kiểm thử tính đúng đắn vòng lặp Nếu vòng lặp trong đường kiểm thử xác định được số lần lặp tối đa thì số đường đi mới sinh ra là bảy Ngược lại, nếu vòng lặp không xác định số lần lặp tối đa thì số đường đi mới sinh ra là bốn
Với mã nguồn chứa vòng lặp, kiểm thử động sử dụng kĩ thuật phủ định hệ để sinh ca kiểm thử kế tiếp nên số ca kiểm thử có thể rất lớn hoặc không xác định
Trường hợp số ca kiểm thử không xác định xảy ra khi số lần lặp không được
biết trước như ―while (m!=n){ }‖, trong đó m và n là hai tham số kiểu nguyên truyền vào
hàm Để giải quyết hai vấn đề này, một vài công cụ kiểm thử như PathCrawler chèn thêm
mã nguồn xác định số lần lặp tối đa của mỗi vòng lặp hoặc thêm yêu cầu thời gian chạy Tuy nhiên, nhìn chung số ca kiểm thử vẫn khá lớn gây khó khăn cho quản lí
Tầm quan trọng của tự động hóa QTKT hộp trắng dòng điều khiển
Một số những nguyên nhân chính dẫn đến vấn đề tự động hóa quy trình kiểm thử hộp trắng dòng điều khiển gồm: Thời gian sinh ca kiểm thử thủ công là khá lâu và
dễ dẫn đến sai sót Nguyên nhân chính phụ thuộc vào trình độ chuyên môn của kiểm thử viên, độ phức tạp mã nguồn và chịu áp lực bởi môi trường làm việc Mặt khác chi phí về nguồn nhân lực cho pha kiểm thử khá tốn kém Muốn đảm bảo chất lượng phần mềm (đặc biệt với dự án lớn) thì chi phí nguồn nhân lực càng cao Do đó, vấn đề quản
lí khối lượng nguồn nhân lực trở nên phức tạp và rắc rối Các thống kê cho thấy chi phí pha kiểm thử có thể chiếm tới 40%-60% tổng chi phí phát triển dự án phần mềm [25] Các phần mềm hệ thống, phần mềm doanh nghiệp, v.v đều đòi hỏi chất lượng cao nên pha kiểm thử luôn được chú trọng và không thể bỏ qua Hơn nữa, mỗi khi phần mềm được nâng cấp thì quá trình kiểm thử được tiến hành lại dẫn đến chi phí đã cao nay càng cao hơn
1.4 Thách thức trong kiểm thử phần mềm
Tồn tại các ý tưởng không đúng về kiểm thử như: Có thể kiểm thử phần mềm
đầy đủ, nghĩa là đã vét cạn mọi hoạt động kiểm thử cần thiết; Có thể tìm tất cả lỗi nếu
kỹ sư kiểm thử làm tốt công việc của mình; Tập các ca kiểm thử tốt phải chứa rất nhiều ca kiểm thử để bao phủ rất nhiều tình huống; Ca kiểm thử tốt luôn là ca kiểm thử có độ phức tạp cao; Tự động kiểm thử có thể thay thế kỹ sư kiểm thử để kiểm thử phần mềm một cách tốt đẹp; Kiểm thử phần mềm thì đơn giản và dễ dàng Ai cũng có
thể làm, không cần phải qua huấn luyện
Trang 29Ngoài ra, việc kiểm thử còn gặp nhiều hạn chế bao gồm: Không thể chắc là
các đặc tả phần mềm đều đúng 100%; Không thể chắc rằng hệ thống hay công cụ kiểm thử là đúng; Không có công cụ kiểm thử nào thích hợp cho mọi phần mềm; Kỹ
sư kiểm thử không chắc rằng họ hiểu đầy đủ về sản phẩm phần mềm; Không bao giờ
có đủ tài nguyên để thực hiệm kiểm thử đầy đủ phần mềm; Không bao giờ chắc rằng
ta đạt đủ 100% hoạt động kiểm thử phần mềm
1.5 Thực thi biểu trưng
1.5.1 Tổng quan về thực thi biểu trưng
Trong khoa học máy tính, thực thi biểu trưng là một phương tiện để phân tích một chương trình để xác định đầu vào nào gây ra mỗi phần của chương trình để thực thi Một bộ biên dịch theo chương trình, giả sử nhận các giá trị biểu trưng cho các đầu vào thay vì nhận các đầu vào cụ thể như thực thi bình thường của chương trình Do
đó, các biểu thức theo các biến biểu trưng được truyền cho các biểu thức và biến trong chương trình cũng như các ràng buộc về các biểu trưng đó cho các kết quả có thể có của mỗi nhánh có điều kiện
Lịch sử hình thành và phát triển thực thi biểu trưng:
1976: Một hệ thống để tạo dữ liệu thử nghiệm và thực hiện các chương trình một cách biểu trưng (Lori Clarke)
1976: Thực thi biểu trưng và thử nghiệm chương trình (James King)
2005-nay: thực hiện biểu trưng thực tế
Một ví dụ về thực thi biểu trưng như sau:
Trang 30Trong ví dụ này, khi thực thi theo cách thông thường, các giá trị rời rạc sẽ được đọc và gán cho y Việc thực thi sau đó sẽ tiến hành nhân và nhánh có điều kiện, sẽ đánh giá thành sai và in OK
Với quá trình thực thi biểu trưng, chương trình đọc một giá trị biểu trưng (ví dụ
là λ) và gán nó cho y Chương trình sau đó sẽ tiến hành nhân và gán λ * 2 cho z Khi đạt đến câu lệnh if, nó sẽ đánh giá λ * 2 == 12 Tại thời điểm này của chương trình, có thể nhận bất kỳ giá trị nào và do đó việc thực thi biểu trưng có thể tiến hành dọc theo
cả hai nhánh, bằng cách "rẽ" hai đường dẫn Mỗi đường dẫn được gán một bản sao của trạng thái chương trình theo lệnh rẽ nhánh cũng như ràng buộc đường dẫn Trong
ví dụ này, ràng buộc đường dẫn là λ * 2 == 12 cho nhánh sau đó và λ * 2! = 12 cho nhánh khác Cả hai đường dẫn có thể được thực hiện một cách biểu trưng độc lập Khi các đường dẫn chấm dứt (ví dụ, do thực thi fail () hoặc đơn giản là thoát), thực thi biểu trưng sẽ tính một giá trị cụ thể cho λ bằng cách giải quyết các ràng buộc đường dẫn tích lũy trên mỗi đường dẫn Các giá trị cụ thể này có thể được coi là trường hợp kiểm thử cụ thể có thể, ví dụ, giúp các nhà phát triển tái tạo lỗi Trong ví dụ này, bộ giải ràng buộc sẽ xác định rằng để đạt được câu lệnh fail (), λ sẽ cần bằng 6
Một chương trình P có thể xem xét như một hàm, P : S→ R , trong đó S là tập hợp các đầu vào (input) có thể và R là tập hợp các đầu ra (output) có thể S có thể được biểu diễn bởi vector I=(x1,…,xk,…,xn), trong đó xk là tham số đầu vào thứ k của
P với k N Một bộ giá trị i=(d1, ,dk,…,dn) biểu thị cho một đầu vào của P, i S, trong đó dk là các giá trị cụ thể sao cho dk Dxk với Dxk là miền giá trị của tham số đầu vào xk Sự thực thi của chương trình P với đầu vào i S được biểu thị bởi P(i)
Biểu đồ luồng điều khiển (CFG) của một chương trình P là một bộ G=(N, E, s, e), trong đó G là một đồ thị có hướng, với N là tập hợp các nút (node), E = {(n,m) | n,m
N} là tập hợp các cạnh, s là nút vào và e là nút ra, s và e là duy nhất Mỗi nút được
định nghĩa như một khối cơ bản (basic block) là một dãy liên tục các chỉ thị (câu lệnh)
sao cho luồng điều khiển khi đi vào nút và ra khỏi nút không bị ngưng lại (halt) Điều này có nghĩa là nếu bất cứ câu lệnh nào của block được thực thi thì toàn bộ block được thực thi Mỗi cạnh của CFG nối 2 nút với nhau và được gán nhãn với một biểu thức điều kiện rẽ nhánh Nếu cạnh không được gán nhãn có nghĩa là điều kiện luôn đúng
Một đường đi (path) cụ thể là dãy các nút: p=(p1, p2,…,pn) với pn là nút cuối của đường đi p và (pi,pi+1) E (1 < i < n-1) Nếu tồn tại i S sao cho sự thực thi P(i)
Trang 31đi theo đường đi p thì p gọi là đường đi khả thi, ngược lại p là đường đi không khả thi Một đường đi bắt đầu tại nút vào và kết thúc tại nút ra gọi là đường đi đầy đủ, nếu kết thúc tại nút không phải là nút ra thì gọi là đường đi không đầy đủ (path segment) Một chương trình P cũng có thể xem gồm tập hợp các câu lệnh (statements) là thành phần nhỏ nhất trong một chương trình mà có thể được thực thi riêng rẽ Bằng việc thực thi một câu lệnh chương trình có thể chuyển đổi trạng thái thực thi của nó từ trạng thái hiện thời tới trạng thái mới Một đường đi thực thi của chương trình P là một dãy các câu lệnh mà có thể được thực thi theo thứ tự từ điểm bắt đầu của chương trình Đoạn đường đi đầu tiên (path prefix) có độ dài n của đường đi thực thi p là một dãy bao gồm n câu lệnh đầu tiên của p
Do đó việc sinh dữ liệu kiểm thử cho chương trình là việc sinh một tập hợp tối thiểu các đầu vào i Є S sao cho có thể thực thi tất cả các đường đi trong CFG của chương trình được kiểm thử
Một vài hạn chế của thực thi biểu trưng gồm:
Bùng nổ đường đi: Biểu trưng thực hiện tất cả các đường dẫn chương trình khả thi không mở rộng ra các chương trình lớn Số lượng đường dẫn khả thi trong một chương trình tăng theo cấp số nhân với sự gia tăng kích thước chương trình và thậm chí có thể là vô hạn trong trường hợp các chương trình có các vòng lặp không giới hạn [25] Các giải pháp cho vấn đề bùng nổ đường dẫn thường sử dụng phương pháp phỏng đoán để tìm đường dẫn để tăng độ bao phủ mã [26] giảm thời gian thực hiện bằng cách song song các đường dẫn độc lập [27] hoặc bằng cách hợp nhất các đường dẫn tương tự [28]
Hiệu quả phụ thuộc vào chương trình: Thực thi biểu trưng được sử dụng để lý giải về đường dẫn chương trình, đó là một lợi thế so với lý do về đầu vào của chương trình như các mô hình kiểm thử khác sử dụng (ví dụ: phân tích chương trình động) Tuy nhiên, nếu ít đầu vào đi theo cùng một đường dẫn qua chương trình, thì sẽ có rất
ít tiết kiệm so với việc kiểm tra riêng từng đầu vào
Bí danh bộ nhớ: Việc thực thi biểu trưng khó hơn khi cùng một vị trí bộ nhớ có
thể được truy cập thông qua các tên khác nhau (bí danh) Bí danh không thể luôn luôn được nhận dạng tĩnh, do đó, công cụ thực thi biểu trưng không thể nhận ra rằng một thay đổi đối với giá trị của một biến cũng thay đổi biến khác [29]
Mảng: Vì một mảng là một tập hợp của nhiều giá trị riêng biệt, nên thực thi
biểu trưng phải coi toàn bộ mảng là một giá trị hoặc coi mỗi phần tử mảng là một vị
Trang 32trí riêng biệt Vấn đề với việc xử lý riêng từng phần tử mảng là một tham chiếu như
"A [i]" chỉ có thể được chỉ định động, khi giá trị cho i có giá trị cụ thể [29]
Việc thực thi biểu trưng đã được triển khai ở cấp độ ngôn ngữ trung gian - đáng chú ý là KLEE, hoạt động ở cấp độ LLVM IR Một trình biên dịch IR có sức mạnh trong ngành như LLVM, trình bày các ưu điểm và nhược điểm để thực thi biểu trưng, xuất phát từ độ chính xác cao với các tính năng ngôn ngữ và nền tảng đích được tính đến (ví dụ: hành vi không xác định, các quy ước gọi, v.v.) Độ chính xác này cho phép một công cụ thực thi mang tính biểu trưng để phát hiện các lỗi cấp thấp, nhưng cũng tăng thêm độ phức tạp, về mặt thời gian chạy, tính năng bổ sung và bảo trì mã Ngược lại, sự đơn giản về cú pháp và ngữ nghĩa của Boogie làm cho nó trở thành một nền tảng lý tưởng để nghiên cứu ban đầu sự kết hợp giữa thực thi biểu trưng với các phân tích khác và thiết kế các tối ưu hóa mới để thực thi biểu trưng hiệu quả hơn
Tương tác môi trường
Các chương trình tương tác với môi trường của chúng bằng cách thực hiện các cuộc gọi hệ thống, nhận tín hiệu, v.v Các vấn đề về tính nhất quán có thể phát sinh khi thực thi đến các thành phần không được kiểm soát bởi công cụ thực thi biểu trưng (kernel hoặc thư viện) Hãy xem xét ví dụ sau:
Trang 33thống trong kernel và nằm ngoài sự kiểm soát của công cụ thực thi biểu trưng Các cách tiếp cận chính để giải quyết thách thức này là:
Thực thi gọi đến môi trường một cách trực tiếp: Ưu điểm của phương pháp này
là đơn giản để thực hiện Nhược điểm là các tác dụng phụ của các cuộc gọi như vậy sẽ làm tắc nghẽn tất cả các trạng thái được quản lý bởi công cụ thực thi biểu trưng Trong
ví dụ trên, hướng dẫn ở dòng 11 sẽ trả về "một số dữ liệu khác dữ liệu khác" hoặc
"một số dữ liệu khác" tùy thuộc vào thứ tự tuần tự của các trạng thái
Mô hình hóa môi trường: Trong trường hợp này, động cơ sẽ gọi hệ thống với
một mô hình mô phỏng hiệu ứng của chúng và giữ tất cả các tác dụng phụ trong lưu trữ theo trạng thái Ưu điểm là người ta sẽ nhận được kết quả chính xác khi thực hiện các chương trình tương tác với môi trường Nhược điểm là người ta cần thực hiện và duy trì nhiều mô hình gọi hệ thống phức tạp Các công cụ như KLEE [30], Cloud9 và Otter [12] thực hiện phương pháp này bằng cách triển khai các mô hình cho các hoạt động của hệ thống tệp, ổ cắm, IPC, v.v
Phân nhánh toàn bộ trạng thái hệ thống: Các công cụ thực thi biểu trưng dựa
trên các máy ảo giải quyết vấn đề môi trường bằng cách loại bỏ toàn bộ trạng thái
VM Cách tiếp cận này làm giảm nhu cầu viết và duy trì các mô hình phức tạp và cho phép hầu như bất kỳ nhị phân chương trình nào được thực thi một cách biểu trưng Tuy nhiên, nó có tổng phí sử dụng bộ nhớ cao hơn
Cách thực hiện thực thi biểu trưng qua một ví dụ đầy đủ:
Hình 1.7 Ví dụ về ý tưởng thực hiện cụ thể của thực thi biểu trưng
Khi x và y được đưa các đầu vào mang tính biểu trưng (Hình 1.7) QTKT thực hiện như sau:
i Thực hiện chương trình trên các giá trị biểu trưng
ii Trạng thái biểu trưng ánh xạ các biến thành giá trị biểu trưng
Trang 34iii Điều kiện đường dẫn (PC) là một công thức logic trên các đầu vào biểu trưng
mã hóa tất cả các quyết định nhánh được thực hiện cho đến nay
iv Tất cả các đường dẫn trong chương trình tạo thành cây thực thi của nó, trong
đó một số đường dẫn là khả thi (feasible) và một số đường dẫn là không khả thi (infeasible)
Ứng dụng của thực thi biểu trưng:
Thực thi biểu trưng được sử dụng rộng rãi trong thực tế Các công cụ dựa trên thực thi biểu trưng đã tìm thấy các lỗi nghiêm trọng và lỗ hổng bảo mật trong các hệ thống khác nhau như các hệ thống máy chủ mạng, hệ thống tập tin, trình điều khiển thiết bị, tiện ích Unix, thị giác máy vv
Thực thi Concolic: Kết hợp cả thực thi biểu trưng và thực thi cụ thể (bình
thường) Ý tưởng cơ bản là để thực thi cụ thể định hướng thực thi biểu trưng Ở đây, chương trình chạy như bình thường (nó cần được cung cấp một số đầu vào), nhưng ngoài ra nó cũng duy trì thông tin biểu trưng thông thường
Thực thi biểu trưng so với diễn giải trừu tượng:
Có phải Thi hành biểu trưng là một ví dụ của Giải thích trừu tượng? Chẳng hạn, SE có phải là một trình thông dịch trừu tượng trên miền trừu tượng của công thức logic, nơi chúng ta không thực hiện các phép nối?
Thực thi biểu trưng là một kỹ thuật phổ biến để phân tích các chương trình lớn hoàn toàn tự động, dựa vào các bộ giải SMT
• Để chấm dứt, có thể cần các vòng lặp ràng buộc dẫn đến gần đúng
• Để xử lý các ràng buộc phi tuyến tính và môi trường bên ngoài, trộn lẫn việc thực thi cụ thể và thực thi biểu trưng (được gọi là thực thi đồng thời) cũng dẫn đến sự gần đúng
1.5.2 Thực thi biểu trưng tĩnh
Ý tưởng chính của thực thi biểu trưng [31] là thực thi chương trình với các giá trị biểu trưng thay vì các giá trị cụ thể của các tham số đầu vào
Với mỗi tham số đầu vào một giá trị biểu trưng được đưa ra để kết hợp với nó Mỗi biến trong chương trình P mà giá trị của nó phụ thuộc vào giá trị của các tham số đầu vào thì trong quá trình thực thi biểu trưng một giá trị biểu trưng sẽ được tính toán
để kết hợp cùng với nó Mỗi giá trị biểu trưng biểu thị cho một tập hợp các giá trị cụ thể mà một biến hoặc một tham số đầu vào có thể nhận Kết quả trả về của một
Trang 35chương trình được thực thi tương trưng nếu có cũng được biểu thị bởi biểu thức của các giá trị biểu trưng
Giá trị biểu trưng của biến x có thể được biểu thị bởi:
(a) Một ký hiệu đầu vào
(b) Một biểu thức kết hợp giữa các giá trị biểu trưng bởi các toán tử,
(c) Một biểu thức kết hợp giữa giá trị biểu trưng và giá trị cụ thể bởi toán tử Một ký hiệu đầu vào biểu thị cho giá trị biểu trưng của một tham số đầu vào lúc bắt đầu thực thi chương trình Các tham số đầu vào khác nhau của P được biểu thị bởi các ký hiệu đầu vào khác nhau Các toán tử là các phép toán như cộng (+), trừ (), nhân (*), chia (/)
Nếu giá trị của một biến x không phụ thuộc vào các giá trị đầu vào thì không có giá trị biểu trưng nào được tính toán để kết hợp với nó Giá trị biểu trưng của các biến
và các tham số đầu vào được cập nhật như các giá trị cụ thể của nó trong quá trình thực thi
Trạng thái của một chương trình được thực thi tượng trưng bao gồm các giá trị của các biến trong chương trình, điều kiện đường đi (Path Condition - PC) và biến đếm chương trình Biến đếm chương trình xác định chỉ thị (câu lệnh) tiếp theo sẽ được thực thi Mỗi PC là một biểu thức kết hợp bởi các ràng buộc mà các giá trị đầu vào chương trình cần thỏa mãn để chương trình được thực thi theo đường đi tương ứng với
PC đó Mỗi ràng buộc là một biểu thức biểu trưng dạng x*y trong đó x là giá trị biểu trưng , y là giá trị biểu trưng hoặc giá trị cụ thể và * là một trong các phép toán ≤, ≠,
=, <, >, ≥ Các ràng buộc đó chính là biểu thức của điều kiện rẽ nhánh và biểu thức phủ định của điều kiện rẽ nhánh tương ứng với nhánh true và nhánh false Tại mỗi câu lệnh rẽ nhánh, các ràng buộc được tạo ra Các ràng buộc này được biểu thị bởi biểu thức của các giá trị biểu trưng hay biểu thức của giá trị biểu trưng và giá trị cụ thể phụ thuộc vào biến xuất hiện trong biểu thức điều kiện của câu lệnh rẽ nhánh có giá trị biểu trưng được tính toán để kết hợp với nó hay không
Trong quá trình thực thi biểu trưng, việc chương trình được thực thi theo một đường đi cụ thể nào đó không phụ thuộc vào các giá trị cụ thể của các biến và các tham số đầu vào Tại các điểm rẽ nhánh, cả hai nhánh ra sẽ được xem xét để điều hướng sự thực thi hiện thời đi theo SE chủ yếu liên quan tới việc thực thi hai loại câu lệnh đó là câu lệnh gán và câu lệnh rẽ nhánh Tại các câu lệnh gán thì giá trị biểu
Trang 36trưng của các biến chương trình cũng như các tham số đầu vào có liên quan tới câu lệnh gán đó được cập nhật Tại các câu lệnh rẽ nhánh, chương trình sẽ được điều hướng để thực thi theo cả hai nhánh Và hai ràng buộc đường đi tương ứng với hai nhánh sẽ được tạo ra Một ràng buộc là biểu thức điều kiện tại câu lệnh rẽ nhánh Còn ràng buộc kia là phủ định của biểu thức điều kiện rẽ nhánh Các ràng buộc này sẽ được cập nhật vào điều kiện đường đi tương ứng với các nhánh đó Đồng thời các PC này sẽ được đánh giá để xác định đường đi tương ứng với PC đó có khả thi Nếu PC được đánh giá trở thành false thì SE sẽ quay lui và chỉ thực thi theo nhánh khả thi Các
PC được tạo ra bằng cách thu gom các ràng buộc trên các đường đi tương ứng và giải quyết các ràng buộc này sẽ sinh ra các giá trị cụ thể cho các tham số đầu vào
Để mô tả sự thực thi biểu trưng một chương trình Một cây thực thi biểu trưng (Symbolic Execution Tree - SET) được đưa ra để biểu thị cho các đường đi thực thi trong quá trình thực thi biểu trưng một chương trình Các nút biểu thị cho các trạng thái của chương trình được thực thi biểu trưng và các cạnh biểu thị cho sự chuyển đổi trạng thái từ trạng thái này sang trạng thái khác
public void Swap(int x, int y){
1: if (x > y) { 2: x = x + y;
3: y = x - y;
4: x = x - y;
5: if (x - y > 0) 6: assert(false);
}
Hình 1.8 Cây thực thi biểu trưng
Trang 37Cây thực thi biểu trưng (Hình 1.8) biểu thị cho việc thực thi biểu trưng hàm Swap Bắt đầu thực thi biểu trưng hàm Swap bằng cách gán giá trị biểu trưng cho các tham số đầu vào x và y lần lượt là X và Y, đồng thời khởi tạo PC là true Tới câu lệnh
rẽ nhánh 1, cả hai nhánh đi của chương trình đều chọn để thực thi với các giá trị biểu trưng Tại câu lệnh này, biểu thức điều kiện rẽ nhánh và biểu thức phủ định của điều kiện rẽ nhánh được thêm vào PC theo các nhánh tương ứng Trong thực thi biểu trưng , nếu điều kiện rẽ nhánh được thêm vào PC thì PC đó tương ứng với PC của nhánh mà điều kiện rẽ nhánh nhận giá trị true Sau khi thực thi câu lệnh 1, hàm Swap tiếp tục được thực thi theo nhánh mà điều kiện rẽ nhánh ở câu lệnh 1 nhận giá trị true Khi thực thi các câu lệnh gán 2, 3, 4 thì giá trị của các biến được cập nhật với giá trị mới Khi tới câu lệnh rẽ nhánh 5, thêm hai nhánh đi mới được xem xét để thực thi với các giá trị biểu trưng PC tiếp tục được cập nhật theo các nhánh tương ứng
Tại đây, PC được cập nhật với điều kiện rẽ nhánh ở 5 trở thành false do không tồn tại bộ giá trị nào thỏa mãn PC Vì vậy hàm Swap chỉ thực thi theo nhánh mà PC được cập nhật với biểu thức phủ định của điều kiện rẽ nhánh tại 5 Và câu lệnh 6 sẽ không bao giờ được thực thi
Tại mỗi điểm rẽ nhánh, PC được cập nhật và một bộ xử lý ràng buộc được sử dụng để xác định nhánh tương ứng với PC đó có khả thi hay không để điều hướng việc thực thi hiện thời đi theo nhánh đó Nếu PC được đánh giá tới false thì SE sẽ quay lui và chỉ thực thi chương trình theo nhánh mà PC được đánh giá tới true
1.5.3 Thực thi biểu trưng động
Thực thi biểu trưng động [32, 33] là kỹ thuật thực thi tượng trưng dựa trên phân tích chương trình động Thực thi biểu trưng động chính là sự kết hợp giữa thực thi các giá trị cụ thể và thực thi với các giá trị biểu trưng Trong thực thi biểu trưng động, chương trình được thực thi nhiều lần với những giá trị khác nhau của tham số đầu vào
Bắt đầu bằng việc chọn những giá trị tùy ý cho các tham số đầu vào và thực thi chương trình với những giá trị cụ thể đó Với những giá trị cụ thể này thì chương trình
sẽ được thực thi theo một đường đi xác định Thực thi chương trình với các giá trị cụ thể của tham số đầu vào và thu gom các ràng buộc trong quá trình thực thi theo đường
đi mà sự thực thi cụ thể này đi theo, đồng thời suy ra các ràng buộc mới từ những ràng buộc đã thu gom được
Trang 38Tại các câu lệnh rẽ nhánh, biểu thức điều kiện rẽ nhánh sẽ được đánh giá phụ thuộc vào các giá trị cụ thể của các tham số đầu vào Nếu biểu thức điều kiện rẽ nhánh nhận giá trị là true thì biểu thức của điều kiện rẽ nhánh sẽ được thu gom vào ràng buộc của PC và được ghi nhớ, đồng thời phủ định của điều kiện rẽ nhánh sẽ được sinh
ra và được thêm vào một PC tương ứng với nhánh còn lại mà sự thực thi cụ thể đó không đi theo Một bộ xử lý ràng buộc sẽ được sử dụng để giải quyết các ràng buộc mới sinh ra này để sinh ra các giá trị cụ thể của tham số đầu vào Ngược lại, nếu là false thì biểu thức phủ định của điều kiện rẽ nhánh sẽ được thu gom vào ràng buộc của
PC tương ứng với nhánh đi mà sự thực thi hiện thời đang đi theo và được ghi nhớ Đồng thời điều kiện rẽ nhánh sẽ được sinh ra và thêm vào PC tương ứng với nhánh đi còn lại mà sự thực thi hiện thời không đi theo Các giá trị mới được sinh ra của các tham số đầu vào sẽ tiếp tục được thực thi và quá trình này sẽ được lặp lại cho tới khi chương trình được thực thi theo tất cả các đường đi
Do các chương trình được thực thi với những giá trị cụ thể nên có thể thấy rằng tất cả các đường đi phân tích được trong quá trình thực thi biểu trưng động đều là các đường đi khả thi
Các bước thực hiện thuật toán thực thi biểu trưng động với các thông tin đầu vào bao gồm :
S : Tập hợp tất cả các câu lệnh của chương trình P
s : Tập con của S (s S)
I : Tập hợp các đầu vào của P
P(i): Thực thi chương trình với đầu vào i I, sao cho s được thực thi
J : Tập hợp các đầu vào của P được thực thi (J={i | P(i)})
C(i): Ràng buộc thu gom được từ việc thực thi P(i), hay còn gọi là điều kiện đường đi
C‟(i): Điều kiện đường đi suy ra từ C(i)
Trang 39Bước 5: Quay lại bước 1
đó thực thi hàm DSE với giá trị null này Khi tới câu lệnh rẽ nhánh 2, điều kiện a==null được thỏa mãn do đó ràng buộc C(i):(a==null) được ghi nhớ Ràng buộc C‘(i) được suy ra bằng cách lấy phủ định của điều kiện rẽ nhánh, C‘(i): (a!=null) Solve (C‘(i)) suy ra được a={}
Tiếp tục thực thi chương trình với giá trị a={} Với a={} khi tới câu lệnh rẽ nhánh 3, biểu thức a.length > 0 nhận giá trị false, ràng buộc C(i): (a!=null) &&
!(a.length >0) được ghi nhớ Ràng buộc C‘(i):(a!=null && a.length > 0) được sinh ra, solve (C‘(i)) ta được giá trị mới của tham số đầu vào là {0}
Tiếp tục thực thi hàm DSE với giá trị a={0} Với giá trị a={0} khi đi tới câu lệnh rẽ nhánh 4, thì biểu thức điều kiện rẽ nhánh nhận giá trị false đo đó ràng buộc C‘(i):( a!=null && a.length>0 && a[0]!=123456789) được ghi nhớ Điều kiện C‘(i): (a!=null && a.length>0 && a[0]==123456789) được sinh ra, solve (C‘(i)) ta được giá trị a={12345678} Đến đây thì không còn đường đi nào của hàm DSE mà chưa được thực thi và qua trình thực thi sẽ được dừng lại
Bảng 1.1 Ví dụ về thực thi biểu trưng động
Ràng buộc C’(i) Input i Ràng buộc được ghi nhớ
C(i)
null a = = null a!=null {} a!=null && !(a.length>0)
a!=null&& a.length>0 {0} a!=null && a.length>0
&& a[0]!=123456789
Trang 40a!=null && a.length>0
Với những hệ thống này, mã nguồn chương trình cần được sửa đổi để cho phép thực thi biểu trưng được thực hiện dọc theo việc thực thi cụ thể Chương trình được thực thi với những giá trị ngẫu nhiên với một chiều sâu (depth) định trước của SET Chiều sâu được sử dụng để giúp cho việc thực thi một chương trình được dừng lại trong trường hợp chương trình có vòng lặp vô tận hoặc các hàm đệ quy Khi chương trình bắt đầu được thực thi thì một cây thực thi tương trưng tương ứng cũng được khởi tạo Trong quá trình thực thi, các giá trị biểu trưng của các biến sẽ đươc tính toán và các ràng buộc đường đi sẽ được sinh ra từ các giá trị biểu trưng đó Với mỗi ràng buộc được sinh ra thì SET sẽ được thêm vào một đỉnh (node) tương ứng với ràng buộc đó Việc xây dựng SET tiến hành trong suốt quá trình thực thi Có thể xem mỗi lần thực thi là mỗi lần duyệt một đường đi của SET
Khi các câu lệnh rẽ nhánh được thực thi, các đường đi trong SET cũng được
mở rộng theo các nhánh đó Với những giá trị cụ thể việc thực thi sẽ đi theo một nhánh cụ thể Nhánh còn lại mà sự thực thi cụ thể đó không đi theo sẽ có một đỉnh mới được tạo ra và được đánh dấu là chưa được thăm Đỉnh mới được tạo ra sẽ lưu các ràng buộc tương ứng với nhánh mà đỉnh đó được thêm vào Sau mỗi lần thực thi, một đỉnh chưa được thăm trong SET sẽ được chọn Ràng buộc đường đi tương ứng với đoạn đường đi từ nút gốc của SET tới đỉnh được chọn đó sẽ được thu gom và được đưa tới một bộ giải ràng buộc để xử lý Nếu ràng buộc đường đi này không thỏa mãn, một đỉnh chưa được thăm khác của SET sẽ được chọn, còn nếu ràng buộc đường đi này thỏa mãn thì bộ xử lý ràng buộc sẽ sinh ra các giá trị đầu vào cụ thể cho lần thực thi tiếp theo Khi các đỉnh tương ứng với các nhánh trong SET đều được thăm hết thì thuật toán sẽ tạm dừng Và các giá trị đầu vào cụ thể được sinh ra cùng với những thông tin phân tích được trong mỗi lần thực thi sẽ được sử dụng để sinh ra các UT và cho mục đích báo cáo Các giá trị đầu vào cụ thể được trả về sau mỗi lần chạy được