Trong những năm gần đây, việc phát triển phần mềm ngày càng được chuyên nghiệp hóa. Các phần mềm được phát triển ngày càng có quy mô lớn. Yêu cầu đảm bảo chất lượng phần mềm là một trong những mục tiêu quan trong nhất, đặc biệt trong một số lĩnh vực như y khoa, ngân hàng, hàng không… Việc kiểm thử, kiểm chứng phần mềm một cách thủ công chỉ đảm bảo được phần nào chất lượng của phần mềm. Vì vậy rất nhiều các tổ chức, công ty đã nghiên cứu và phát triển các lý thuyết cũng như công cụ để kiểm chứng, kiểm thử phần mềm một cách tự động.Xuất phát từ nhu cầu thực tế trên, tác giả đã nghiên cứu một số lý thuyết, công cụ trong việc kiểm chứng và kiểm thử phần mềm. Một lý thuyết nền tảng rất quan trọng đó là lý thuyết về tính thỏa được, viết tắt là SMT (Satisfiability Modulo Theories). Lý thuyết về tính thỏa được đã được ứng dụng để giải quyết nhiều bài toán trong công nghệ phần mềm như:•Kiểm chứng chương trình•Khám phá chương trình•Mô hình hóa phần mềm•Sinh các ca kiểm thử
Trang 1ĐẠI HỌC QUỐC GIA HÀ NỘI
TRƯỜNG ĐẠI HỌC CÔNG NGHỆ
PHAN VĂN TIẾN
NGHIÊN CỨU PHƯƠNG PHÁP SINH DỮ LIỆU KIỂM THỬ PHẦN MỀM DỰA TRÊN KỸ THUẬT KIỂM CHỨNG MÔ HÌNH
LUẬN VĂN THẠC SĨ
Hà Nội - 2011
Trang 2LỜI CẢM ƠN
TRƯỜNG ĐẠI HỌC CÔNG NGHỆ
PHAN VĂN TIẾN
NGHIÊN CỨU PHƯƠNG PHÁP SINH DỮ LIỆU KIỂM THỬ PHẦN MỀM DỰA TRÊN KỸ THUẬT KIỂM CHỨNG MÔ HÌNH
NGÀNH: CÔNG NGHỆ THÔNG TIN CHUYÊN NGÀNH: CÔNG NGHỆ PHẦN MỀM
MÃ SỐ: 60 48 10
LUẬN VĂN THẠC SĨ
NGƯỜI HƯỚNG DẪN KHOA HỌC: TS NGUYỄN TRƯỜNG THẮNG
Hà Nội - 2011
Trang 3LỜI CẢM ƠN
Trước tiên tôi xin gửi lời cảm ơn chân thành và sâu sắc nhất tới TS NguyễnTrường Thắng - Viện công nghệ thông tin - Viện khoa học công nghệ Việt Nam Thầy đãtận tình chỉ bảo, giúp đỡ và truyền đạt cho tôi rất nhiều kiến thức và kinh nghiệm quý báutrong thời gian qua
Tôi xin cảm ơn các thầy giáo, cô giáo trong khoa Công Nghệ Thông Tin, các thầycác cô luôn giành cho tôi những kiến thức, tình cảm và những lời khuyên quý báu
Cuối cùng tôi xin cảm ơn các bạn bè, đồng nghiệp và nhất là các thành viên tronggia đình đã tạo mọi điều kiện tốt nhất, động viên, cổ vũ tôi trong suốt quá trình học tập vànghiên cứu để hoàn thành tốt luận văn tốt nghiệp này
Tác giả
Trang 4LỜI CAM ĐOAN
Tôi xin cam đoan rằng đây là công trình nghiên cứu của tôi trong đó có sự giúp đỡcủa thầy hướng dẫn Các nội dung nghiên cứu và kết quả trong đề tài này là hoàn toàntrung thực
Trong luận văn, tôi có tham khảo đến một số tài liệu của một số tác giả đã được liệt
kê tại phần tài liệu tham khảo ở cuối luận văn
Hà Nội, ngày……tháng……năm……
Tác giả
Phan Văn Tiến
Trang 5MỤC LỤC
MỞ ĐẦU 8
CHƯƠNG 1- CƠ SỞ LÝ LUẬN 10
1.1 Tổng quan kiểm định phần mềm 10
1.2 Các nhóm kiểm định phần mềm 10
CHƯƠNG 2- JAVA PATH FINDER VÀ THỰC THI TƯỢNG TRƯNG 12
2.1 Giới thiệu về JPF 12
2.1.1 JPF có thể kiểm tra những chương trình gì? 13
2.1.2 Kiến trúc mức cao của JPF 14
2.1.3 Khả năng mở rộng của JPF 15
2.1.4 Một số mở rộng của JPF 16
2.2 Thực thi tượng trưng để sinh dữ liệu kiểm thử 17
2.2.1 Thực thi tượng trưng là gì? 17
2.2.2 Thực thi tượng trưng với JPF 18
2.2.3 Hướng dẫn thực thi tượng trưng với JPF 19
2.2.4 Hạn chế 29
CHƯƠNG 3- MICROSOFT Z3 31
3.1 SMT là gì 31
3.2 Z3 là gì 31
3.3 Tại sao lại là Z3? 32
3.4 Kiến trúc của Z3 32
3.5 Định dạng đầu vào 33
3.6 Định dạng SMT-LIB 34
3.6.1 Các chức năng chính của SMT-LIB 34
3.7 Các quan hệ, phương thức, và hằng số 35
3.7.1 Tất cả các phương thức là tuyệt đối ( total) 35
3.7.2 Uninterpreted function và hằng số 36
3.7.3 Phương thức đệ quy 36
3.8 Số học 37
3.8.1 Sô học tuyến tính thực 37
3.8.2 Số hoc tuyến tính nguyên 37
3.8.3 Trộn giữa số nguyên và số thực 38
3.8.4 Số học phi tuyến tính 38
Trang 63.9 Kiểu dữ liệu 39
3.9.1 Kiểu bản ghi 39
3.9.2 Kiểu liệt kê ( enumeration) 39
3.9.3 Kiểu dữ liệu đệ qui 39
3.10 Ví dụ về Z3 40
3.11 Một vài ứng dụng của Z3 40
CHƯƠNG 4- TÍCH HỢP Z3 VỚI JPF 42
4.1 Nghiên cứu đánh giá các giải pháp 42
4.2 Kiến trúc hệ thống 42
4.3 Chuyển đổi dữ liệu 43
4.4 Thiết kế và cài đặt 47
4.5 Kết quả và đánh giá 48
KẾT LUẬN VÀ HƯỚNG PHÁT TRIỂN CỦA ĐỀ TÀI 53
TÀI LIỆU THAM KHẢO 54
Trang 7DANH MỤC CÁC HÌN
Hình 2.1: Mô hình hoạt động của JPF 12
Hình 2.2: Sơ đồ trạng thái trong quá trình kiểm thử 13
Hình 2.3: Kiến trúc mức cao 14
Hình 2.4: Mẫu Listener 15
Hình 2.5: Ví dụ về thực thi tượng trưng 18
Hình 2.6: Đầu ra trên Eclipse cho MyClass1 21
Hình 2.7: Đầu ra của MyClass2 trên Eclipse 22
Hình 2.8: Đầu ra của MyClass2sau khi đã lọc kết quả trên Eclipse 24
Hình 2.9: Đầu ra của MyDriver trên Eclipse 25
Hình 2 10: Đầu ra của MyClassFP trên Eclipse 27
YHình 3.1: Kiến trúc của Z3 33
YHình 4.1: Kiến trúc hệ thống 43
Hình 4.2: Sơ đồ mức gói 47
Hình 4.3: Sơ đồ lớp tổng quát 48
Hình 4.4: Kết quả với Choco - số học tuyến tính 49
Hình 4 5: Kết quả với z3 - số học tuyến tính 50
Hình 4 6: Kết quả với Choco – số học phi tuyến tính 51
Hình 4 7: Kết quả với Z3 – số học phi tuyến tính 52
Trang 8MỞ ĐẦU
Trong những năm gần đây, việc phát triển phần mềm ngày càng được chuyênnghiệp hóa Các phần mềm được phát triển ngày càng có quy mô lớn Yêu cầu đảm bảochất lượng phần mềm là một trong những mục tiêu quan trong nhất, đặc biệt trong một sốlĩnh vực như y khoa, ngân hàng, hàng không… Việc kiểm thử, kiểm chứng phần mềmmột cách thủ công chỉ đảm bảo được phần nào chất lượng của phần mềm Vì vậy rấtnhiều các tổ chức, công ty đã nghiên cứu và phát triển các lý thuyết cũng như công cụ đểkiểm chứng, kiểm thử phần mềm một cách tự động
Xuất phát từ nhu cầu thực tế trên, tác giả đã nghiên cứu một số lý thuyết, công cụtrong việc kiểm chứng và kiểm thử phần mềm Một lý thuyết nền tảng rất quan trọng đó là
lý thuyết về tính thỏa được, viết tắt là SMT (Satisfiability Modulo Theories) Lý thuyết vềtính thỏa được đã được ứng dụng để giải quyết nhiều bài toán trong công nghệ phần mềmnhư:
Trong quá trình nghiên cứu về kiểm chứng chương trình tác giả cũng có tìm hiểu
về JavaPathFinder (JPF) JPF là một dự án mã nguồn mở được phát triển trên ngôn ngữJava Hiện nay có một mở rộng của JPF trong việc sinh tự động dữ liệu đầu vào để kiểmthử chương trình Tuy nhiên còn rất nhiều hạn chế, vì vậy tác giả đã nghĩ đến việc làm sao
để tích hợp được Z3 với JPF để có thể sinh tự động dữ liệu kiểm thử chương trình Nếuviệc tích hợp thành công thì sẽ dẫn tới việc giải quyết được lớp bài toán rộng hơn Điềunày là rất có ý nghĩa đối với thực tế
Mục tiêu đề tài:
Mục tiêu của đề tài là nghiên cứu nắm bắt rõ về Z3 và JPF Sau đó bước đầu tíchhợp thành công Z3 và JPF để có thể sinh tự động dữ liệu kiểm thử chương trình Java chocác bài toán mà hiện nay JPF không thể thực hiện được (ví dụ: sinh tự động dữ liệu cho
số học phi tuyến tính)
Trang 9CẤU TRÚC CỦA LUẬN VĂN
Luận văn bao gồm các phần sau:
Mở đầu: Giới thiệu về đề tài, tính cấp thiết cũng như mục tiêu của đề tài
Chương 1: Cơ sở lý luận
Chương 2: JPF và Thực thi tượng trưng
Nội dung: Giới thiêu JPF là gì? Kiến trúc của JPF, cách mở rộng, phát triển trên JPF Ngoài ra còn một phần rất quan trọng đó là giới thiệu về thực thi tượng trưng để sinh dữ liệu kiểm thử cho chương trình trong JPF Mở rộng này sẽ cho phép sinh tự động dữ liệu kiểm thử chương trình Java.
Kết luận và hướng phát triển của luận văn
Trình bày kết quả sau khi nghiên cứu, triển khai và hướng phát triển tiếp theo.
Trang 10CHƯƠNG 1- CƠ SỞ LÝ LUẬN
1.1 Tổng quan kiểm định phần mềm
Như chúng ta đã biết, việc kiểm thử phần mềm là một khâu không thể thiếu trongcác bước phát triển phần mềm, đặc biệt các phần mềm lớn, nhiều module do nhiều ngườiphát triển, dễ sinh ra các lỗi tiềm ẩn mà nhà phát triển không thể lường trước Trong lĩnhvực kiểm định chất lượng phần mềm hiện nay trên thế giới, hiện có nhiều kỹ thuật nhưngtựu chung có thể phân theo ba nhóm chính: Phân tích mã nguồn tĩnh (static codeanalysis), kiểm thử dữ liệu động (dynamic data testing) và kỹ thuật hình thức dựa trên môhình (model-based verification) Hai nhóm đầu tập trung vào việc nâng cao chất lượngphần mềm tại mức mã nguồn, trong khi nhóm cuối cùng xử lý phần mềm tại mức trừutượng cao hơn – mô hình
1.2 Các nhóm kiểm định phần mềm
Phân tích mã nguồn tĩnh là kỹ thuật phát hiện lỗi chương trình mà không yêu cầu chạy chương trình đó Không giống như kỹ thuật kiểm thử dữ liệu động đòi hỏi phải
chạy chương trình với dữ liệu đầu vào thật, kỹ thuật phân tích mã nguồn tĩnh chỉ xem xét
mã nguồn của chương trình
Kỹ thuật kiểm thử phần mềm dựa trên mô hình: khác với hai nhóm ở trên ở
điểm đối tượng được kiểm thử là các mô hình được trừu tượng hóa từ hệ thống được xemxét Quá trình trừu tượng hóa là việc lược bỏ những chi tiết của hệ thống trong khi chỉ giữlại những thông tin/khía cạnh quan trọng cần được lưu tâm Kỹ thuật trừu tượng hóa đơngiản hóa hệ thống được xem xét và do đó giảm không gian tìm kiếm và thời gian phântích chương trình đi nhiều lần so với lúc thực hiện công việc phân tích đó trên mã nguồn
Khi xây dựng xong phần mềm, chúng ta phải sử dụng các testcase (trường hợpkiểm thử) cho việc kiểm thử Chất lượng của việc kiểm thử phụ thuộc rất lớn vào tập hợpcác testcase mà chúng ta sử dụng Hai tiêu chí chính của việc đánh giá chất lượng kiểmthử đó là hiệu quả cho chất lượng phần mềm được kiểm thử là độ phủ dòng chảy (controlflow coverage) và độ phủ dữ liệu (data coverage) Tiêu chí thứ nhất tập trung vào việckiểm thử tất cả các điểm điều khiển trên chương trình (ví dụ: các nhánh rẽ khả đạt trongcấu trúc chương trình – reachable control points) Trong khi tiêu chí thứ hai tập trung vàotập dữ liệu kiểm thử ứng với mỗi điểm điều khiển trong cấu trúc chương trình
Bằng kỹ thuật phân tích chương trình dựa trên mô hình sau khi trừu tượng hóa mãnguồn của chương trình được kiểm thử, việc phân tích cấu trúc logic của chương trình vàtập dữ liệu ứng với mỗi điểm điều khiển trong chương trình sẽ dễ dàng hơn Qua đó, quá
Trang 11trình sinh ra tập các testcase sẽ nhanh chóng và chính xác, đảm bảo các tiêu chí controlflow và data coverage tốt hơn nhiều so với cách tiếp cận ở mức mã nguồn truyền thống.Hơn nữa, nếu quá trình này được thực hiện một cách tự động sẽ giảm thiểu nhiều côngsức cho các chuyên gia kiểm thử chương trình Với cách tiếp cận như vậy, phần mềm cóthể được kiểm thử một cách tự động bằng máy, đem lại kết quả chuẩn hơn, xét đượcnhiều trường hợp hơn, đặt biệt là các lỗi logic, tiết kiệm chi phí sản xuất.
Đánh giá tập dữ liệu kiểm thử: Ngoại trừ những chương trình đơn giản, sẽ là
không thực tế nếu kiểm chứng phần mềm trên tập tất cả dữ liệu đầu vào có thể Ngay cảkhi chỉ tính tổ hợp của các dữ liệu đầu vào hoặc tổ hợp của các hàm, số lượng đầu vào và
số lượng các trạng thái cũng là quá lớn Khi hệ thống có bộ nhớ lớn, các dữ liệu đầu vào,đầu ra sẽ được log lại để theo dõi trạng thái Trong khi không có một công cụ để tạo ramột thiết kế phần mềm chuẩn, hoàn chỉnh và chắc chắn thì việc kiểm thử là một khâukhông thể thiếu để có thể đánh giá được chất lượng phần mềm Vì thế người ta phải tìmcách chọn được một tập dữ liệu nhỏ mà có thể kiểm thử mang lại được độ tin cậy cao vớimỗi hệ thống
Độ phủ hay mức độ đầy đủ bằng trực quan đánh giá được phạm vi hay mức độkiểm thử Nếu kiểm thử không đầy đủ được hết mọi khía cạnh của phần mềm đồng nghĩavới việc chúng ta bỏ sót nhiều lỗi Các tấn suất của các trường hợp cũng không giốngnhau
Khái niệm ca kiểm thử đơn giản là kiểm chứng các trạng thái đưa ra thể hiện chohoạt động của hệ thống Chúng ta có thể tạo ra ca kiểm thử đề đạt được trạng thái có thểbằng cách đưa vào các biến đặc biệt, trạng thái để điều khiển hệ thống
Trang 12CHƯƠNG 2- JAVA PATH FINDER VÀ
THỰC THI TƯỢNG TRƯNG
Trong chương này sẽ bao gồm hai phần chính Phần 1 giới thiệu về JPF, một dự án
mã nguồn mở được viết bằng ngôn ngữ java để kiểm chứng mô hình Phần 2 giới thiệumột mở rộng của JPF đó là thực thi tượng trưng trong việc sinh tự động dữ liệu để kiểmthử chương trình Java
2.1 Giới thiệu về JPF
JPF là một bộ kiểm tra mô hình phần mềm trạng thái tường minh cho Java [5].Hiểu một cách cơ bản JPF là một máy ảo thực thi chương trình Java không chỉ một lần(giống như các máy ảo thông thường), mà thực thi trong tất cả các nhánh, các đường đi cóthể JPF sẽ kiểm tra các vi phạm thuộc tính như khóa chết hoặc các ngoại lệ không thể bắtđược xuyên xuốt các đường thực thi tiềm năng Hình 2-1 mô tả mô hình hoạt động củaJPF
Hình 2.1: Mô hình hoạt động của JPF
Về lý thuyết điều này là rất khả thi, tuy nhiên với việc tăng kích cỡ của ứng dụng,phần mềm kiểm chứng mô hình phải đối mặt với nhiều thách thức JPF cũng không làngoại lệ Câu trả lời của chúng ta đó là tăng sự linh hoạt của JPF để thích nghi với mộtứng dụng cụ thể Chúng ta có thể coi JPF như là một Framework và từ đó phát triển mởrộng để có thể giải quyết được bài toán cụ thể mà chúng ta muốn
Trang 132.1.1 JPF có thể kiểm tra những chương trình gì?
JPF có thể kiểm tra tất cả các chương trình Java JPF có thể tìm ra các khóa chếthoặc ngoại lệ Ngoài ra chúng ta có thể tự phát triển mở rộng để kiểm tra các thuộc tínhkhác Để hiểu rõ hơn về JPF chúng ta có thể xét ví dụ sau:
Tạo một lớp là Rand.java như bên dưới, sau đó chúng ta sẽ dùng JPF để kiểm traxem có lỗi không
import java.util.Random;
public class Rand {
public static void main (String[] args) {
Random random = new Random(42); // (1)
Trang 14Hoạt động của lớp trên đó là khởi tạo 2 biến a và b một cách ngẫu nhiên trong cáckhoang tương ứng la [0,2] và [0,3] Sau đó có một biến c có giá trị được xác định bằngcông thức c = a/(b+a-2).
Nếu ta chạy chương trình java này thông thường thì có thể thấy kết quả là: a = 1, b
=0, và c = -1 Như vậy chương trình là không có lỗi Tuy nhiên nếu ta sử dụng JPF đểkiểm tra chương trình trên thì sẽ thấy như hình vẽ bên dưới:
Nhìn hình vẽ trên ta có thể thấy nếu chạy chương trình java bình thường thì ta chỉ
có thể nhân được 1 trong 6 kết quả trên, do vậy khả năng lớn là không phát hiện được ralỗi ( Đường bôi đỏ là ví dụ) Tuy nhiên JPF sẽ tìm ra tất cả các đường đi của chương trìnhsau đó kiểm tra chúng Ta sẽ thấy có 2 trường hợp lỗi gây ra bởi phép chia cho 0
2.1.2 Kiến trúc mức cao của JPF
Hình 2.3: Kiến trúc mức cao
Trang 15Hình 2-3 biểu diễn sơ đồ kiến trúc mức cao của JPF JPF được thiết kế thành 2thành phần chính đó là: JVM, và Search.
JVM là một bộ sinh trạng thái cụ thể Java Bằng việc thực hiện các chỉ thị Javabytecode
Search chịu trách nhiệm lựa chọn trạng thái mà JVM nên xử lý, hoặc hướng JVMsinh trạng thái tiếp theo, hoặc yêu cầu JVM quay trở lại một trạng thái trước đó Nói mộtcác khác Search có thể coi như các driver cho các đối tượng JVM Search cũng cấu hình
và đánh giá các đối tượng thuộc tính Các cài đặt chính của Search bao gồm tìm kiếm theo
độ sâu (DFSearch) và HeuristicSearch Một cài đặt Search sẽ cung cấp một phương thứcSearch đơn giản bao gồm một vòng lặp chính sẽ duyệt qua tất cả các không gian trạngthái liên quan cho đến khi nó duyệt xong tất cả hoặc tìm ra một vi phạm thuộc tính(property violation)
2.1.3 Khả năng mở rộng của JPF
Hình 2.4: Mẫu Listener
Trang 16JPF có thể được coi như là một Framework mà tại đó bất kỳ nhà phát triển nào đều
có thể mở rộng để phục vụ cho một mục đích cụ thể JPF cung cấp một cơ chế mở rộng đểcho phép thêm vào các chức năng mới mà không phải thay đổi trực tiếp cài đặt của Searchhoặc VM
Yêu cầu về khả năng mở rộng có thể đạt được bằng cách sử dụng mẫu Listernertrên hình 2-4 Các thể hiện sẽ tự đăng ký hoặc đăng ký với đối tượng Search/VM, nhậnthông báo khi một đối tượng (Subject) tương ứng thực thi một hoạt động nhất định, và sau
đó có thể tương tác với đối tượng để truy vấn các thông tin bổ sung hoặc điểu khiển hành
vi của đối tượng
Việc thay đổi các khía cạnh của đổi tượng được ánh xạ vào các phương thứcObserver riêng biệt, các thể hiện của đối tượng sẽ được truyền đi như tham số Đối tượngSubject sẽ theo dõi các listener đã đăng ký theo Multicaster
Có 3 mức khác nhau để có thể lấy được thông tin của đối tượng Subject bằng cáchcài đặt listener
Generic – listener cư trú bên ngoài các gói JPF và chỉ sử dụng các thông tin đãđược công khai (public) theo gov.nasa.jpf.Search / VM
Search-specific – listener cư trú bên ngoài gói JPF nhưng sẽ đưa các tham số thôngbáo của đối tượng Subject vào các cài đặt cụ thể (ví dụ:gov.nasa.jpf.search.heuristic.BFSHeuristic), và sử dụng các API của nó để lấy cácthông tin cài đặt cụ thể
Internal - listener cư trú trong các gói cài đặt Subject riêng biêt và truy cập cácthông tin riêng của gói ( private)
2.1.4 Một số mở rộng của JPF
Với kiến trúc mở rộng linh hoạt, hiện nay đã có một số mở rộng được phát triểncho JPF
UI - User Interface Model Checking
Đây là mở rộng cho việc kiểm tra mô hình một lớp đặc biệt của các ứng dụng Java
đó là các chương trình Swing và AWT Mở rộng này được cài đăt như một như viện chuẩn được mô hình hóa MJI (MJI Là viết tắt của: Model Java Interface) nhằm thay thế các chức năng của Swing và AWT để mà các ứng dụng giao diện sử dụng chuẩn của Java
có thể được kiểm thử với các đầu vào khác nhau
symbc - Symbolic Test Data Generation
Mở rộng này sử dụng BytecodeFactory để ghi đè lõi (core) JPF bytecodes nhằmsinh ra các ca kiểm thử riêng biệt Nói tóm lại nó hoạt động bằng cách sử dụng các thuộc
Trang 17tính/ trường của JPF để thu thập các điều kiện đường đi PC, sau đó được đưa các PC vàomột hệ thống tìm lời giải theo đinh dạng của hệ thống đó để đưa ra dữ liệu kiểm thử Mởrộng này sẽ được trình bày chi tiết hơn ở phần 2.2.
cv - Compositional Verification Framework
Mở rộng này là một thuật toán học máy được sử dụng cho các lập luận thừa nhận/đảm bảo, nhằm mục đích phân chia hệ thống thành các thành phần con và sau đó kiểmchứng từng thành phần đó một cách riêng rẽ Mục đích chính của mở rộng này là cải tiếnkhả năng của JPF, nó có thể được sử dụng để sinh ra môi trường giả định cho kiểm chứng
mô hình UML, để xác định các trình tự sự kiện đúng
numeric - Numeric Property Verification
Mở rộng này được sử dụng để kiểm chứng các thuộc tính của số học Ban đầu mởrộng được sử dụng như như một tập các lớp chỉ thị số học để phát hiện tràn bộ nhớ, sau
đó được mở rộng để kiểm chứng việc truyền giá trị không chính xác, so sánh dấu phẩyđộng chính xác (floating point comparison)
statechart - UML State Chart Model Checking
Mục đích của mở rông này là kiểm tra lược đồ chuyển trạng thái UML Trong mởrộng này mỗi một biểu đồ chuyển trạng thái sẽ được biểu diễn tương ứng với một lớpJava (hoặc nhiều lớp) Sau đó quá trình kiểm tra sẽ là kiểm tra các lớp java đó
2.2 Thực thi tượng trưng để sinh dữ liệu kiểm thử
2.2.1 Thực thi tượng trưng là gì?
Đổi giá trị giữa 2 biến Đường đi cụ thể
Trang 18Hình 2.5: Ví dụ về thực thi tượng trưng
Kỹ thuật thực thi tượng trưng là kỹ thuật thực thi chương trình bằng cách sử dụngcác giá trị tượng trưng, không phải sử dụng các giá trị cụ thể [2] Để hiểu rõ thực thitượng trưng là gì, xét ví dụ chuyển đổi giứa 2 biến x và y:
Ở ví dụ trên, nếu trong trường hợp thực thi tượng trưng, giá trị của x và y là các giátrị tượng trưng X, Y chứ không phải là các giá trị cụ thế Kết quả của quá trình thực thitượng trưng sẽ duyệt hết các dường đi có thể có của chương trình, và cho ra điều kiênđường đi
Ưu điểm của phương pháp này là ta có thể thực thi tại bất kỳ điểm nào trongchương trình và có thể trộn giữa đầu vào tượng trưng với đầu vào cụ thể Phương phápnày sẽ cho ta các điều kiện đường đi của chương trình, và với việc sử dụng các công cụtìm lời giải cho các điều kiện đường đi (coi mỗi điều kiện đường đi là một biểu thức) sẽsinh ra dữ liệu kiểm thử cho chương trình
Tuy nhiên phương pháp này cũng có giới hạn đó là có thể bùng nổ các đường đitrong việc thực thi tượng trưng
2.2.2 Thực thi tượng trưng với JPF
Thực thi tượng trưng là một mở rộng của JPF Mở rộng này của JPF sẽ thực thitượng trưng các chương trình java Một trong những ứng dụng chính của mở rộng này, đó
là tự động sinh dữ liệu kiểm thử bao phủ toàn bộ chương trình của mã nguồn
Trang 19Mở rộng này phối hợp thực thi tượng trưng với kiểm chứng mô hình và các ràngbuộc giải quyết để sinh dữ liệu kiểm thử Trong công cụ này, các chương trình được thựcthi trên đầu vào tượng trưng Các giá trị của các biến được biểu diễn như và các biểu thức
số và ràng buộc, chúng được sinh từ việc phân tích cấu trúc mã nguồn Những ràng buộcsau đó được giải quyết để sinh ra các dữ liệu kiểm thử để đảm bảo đạt được phần mãnguồn đó
Tại thời điểm hiện tại JPF hỗ trợ các tham số nguyên và thực Tuy nhiên vẫn cònmột số trường hợp cần giải quyết cho số thực
Hiện tại mở rộng này chỉ hỗ trợ các ràng buộc tuyến tính (số học tuyến tính), sôhọc phi tuyến là chưa được hỗ trợ Thông tin tượng trưng đươc truyền theo các thuộc tínhkết hợp với các biến và các toán tử Thực thi tượng trưng có thể bắt đầu từ bất kỳ điểmnào trong chương trình và nó có thể thực thi tượng trưng riêng biệt với nhau
2.2.3 Hướng dẫn thực thi tượng trưng với JPF
Để thực hiên một phương thức một cách tượng trưng, người sử dụng cần đặc tảtham số phương thức nào là tượng trưng/cụ thể Các tham biến toàn cục cũng có thể đượcđặc tả để thực thi tượng trưng, theo các sự chú thích đặc biệt Đây là một ví dụ để chạymột thực thi tượng trung Ví dụ này cho phép thực thi tượng trưng của phương thức testtrong lớp chính
Sau đây là một ví dụ rất đơn giản của việc thực thi tượng trưng với JPF Chúng ta
có thể sự dụng Eclipse hoặc thông qua giao diện dòng lệnh
Giả sự ta có phương thức sau trong lớp bạn muốn sinh kiểm thử:
public class MyClass1 {
public int myMethod(int x, int y) {
Trang 20Trong ví dụ đơn giản này, driver chỉ cần gọi myMethod() với số và kiểu tham sốđúng sau đó in ra điều kiện đường đi (Path condition – PC) Điều lưu ý là tham số chínhxác không phải là vấn đề, vì chúng ta sẽ thực thi myMethod() một cách tượng trưng, tất cảcác giá trị cụ thể sẽ được thay thế bằng giá trị tượng trưng.
Chúng ta có thể xem các ca kiểm thử (test case) bằng cách in ra điều kiện đường
đi Việc này thực hiện được bằng cách gọi phương thức:
gov.nasa.jpf.symbc.Debug.printPC() Sau đây là mã nguồn đầy đủ:
public class MyClass1 {
public int myMethod(int x, int y) {
public static void main(String[] args) {
MyClass1 mc = new MyClass1();
int x = mc.myMethod(1, 2);
Debug.printPC("MyClass1.myMethod Path Condition: ");
}
}
Trang 21Khi đó nếu chạy bằng Eclipse sẽ cho kết quả sau:
Hình 2.6: Đầu ra trên Eclipse cho MyClass1
Nhìn vào kết quả ở trên các PC sẽ chỉ ra các ca kiểm thử là
Ca kiểm thử 1: y = -9999999, x = 10000000
Ca kiểm thử 2: y = -10000000, x = 10000000
Ca kiểm thử 1 tương ứng với z > 0 của câu lệnh if của phương thức myMethod
Ca kiểm thử 2 tương ứng với nhánh z≤0
2.2.3.2 Lọc các trường hợp kiểm thử
Chúng ta thay đổi MyClass1 thành MyClass 2 như sau
public class MyClass2 {
private int myMethod2(int x, int y) {
Trang 22// The test driver
public static void main(String[] args) {
MyClass2 mc = new MyClass2();
Hình 2.7: Đầu ra của MyClass2 trên Eclipse
Khi đó chúng ta sẽ nhận được 4 ca kiểm thử như sau:
Ca kiểm thử 1: y = 10000000, x = -9999999
Ca kiểm thử 2: y = -4, x = 5
Trang 23 Ca kiểm thử 3: y = -10000000, x = -10000000
Ca kiểm thử 4: y = -10000000, x = 5
Tuy nhiên giả sử chúng ta chỉ cần quan tâm trong các ca kiểm thử mà lệnh if đượcthực hiện, khi đó chúng ta chỉ cần quan tâm đến ca kiểm thử 2 và 3 Chúng ta có thể chỉchạy JPF như ở trên và lọc chúng một cách thủ công Tuy nhiên có một cách khác tốt hơn
đó là ta sử dụng Verify.ignoreIf() để bắt JPF quay trở lại khi một câu lênh if được tìm rahơn một lần, ví dụ ta có thể thông báo myMethod2() như sau:
import gov.nasa.jpf.jvm.Verify;
import gov.nasa.jpf.symbc.Debug;
public class MyClass2 {
private int myMethod2(int x, int y) {
// The test driver
public static void main(String[] args) {
MyClass2 mc = new MyClass2();
Trang 24 Test Case 1: y = -4, x = 5
Test Case 2: y = -10000000, x = -10000000
Hình 2.8:Đầu ra của MyClass2 sau khi đã lọc kết quả trên Eclipse
2.2.3.3 Bổ sung tiền điều kiện
Giả sử rằng ta muốn giới hạn các ca kiểm thử được sinh ra, nhưng bây giờ vấn đề
là bạn muốn rằng phương thức của bạn sẽ chỉ được gọi với các tham số trong một khoảngnào Ví dụ trong MyClass1.myMethod() bạn tin tưởng rằng x và y được giới hạn trongkhoảng -100 <= x <= 100 và 1<= y <= 3
Để thực hiện điều này trong JPF là rất dễ ràng Thậm chí ta không cần sửa đổiphương thức myMethod() Thay vào đó ta có thể sử dụng tiền điều kiện trong khi cài đặtdriver Chúng ta sẽ cài đặt the driver (gọi là MyDriver1) như sau
import gov.nasa.jpf.symbc.Debug;
public class MyDriver1 {
private static void imposePreconditions(int x, int y) {
MyClass1 mc = new MyClass1();
if (-100 <= x && x <= 100 && 1 <= y && y <= 3) { mc.myMethod(x, y);
Debug.printPC("\nMyClass1.myMethod Path Condition: ");
Trang 25}
}
// The test driver
public static void main(String[] args) {
//Actual arguments are ignored when doing symbolic //execution
imposePreconditions(1,2);
}
}
Chúng ta cần các tiền điều kiện và bởi vì chúng ta không muốn chỉnh sửa lớp, do
đó ta sẽ tạo ra một phương thức gọi tượng trưng như sau:MyDriver1.imposePreconditions(), không phải MyClass1.myMethod() Chú ý rằng tham
số của phương thức imposePreconditions() là x và y, đây chính là tham số củamyMethod() cần phải được symbolic
Hình 2.9: Đầu ra của MyDriver trên Eclipse
Kết quả sẽ cho ra các ca kiểm thử với các tham số nằm trong khoảng giới hạn
Ca kiểm thử 1: y = 1, x = 0
Ca kiểm thử 2: y = 1, x = -100
Trang 262.2.3.4 Các tham số thực
Các phương thức với tham số thực được xử lý một cách chính xác như các tham sốnguyên, mặc dù đầu ra là khác nhau Đây là một ví dụ:
import gov.nasa.jpf.symbc.Debug;
public class MyClassFP {
public double myMethodFP(double x, double y) {
// The test driver
public static void main(String[] args) {
MyClassFP mc = new MyClassFP();
Trang 27Hình 2 10: Đầu ra của MyClassFP trên Eclipse
Khi đó kêt quả ta sẽ được các ca kiểm thử sau: