Đề tài Sinh ca kiểm thử tham số hóa cho chương trình Java

Kiểm thử đơn vị tham số hóa còn đang là một khái niệm mới mẻ đối với nhiều nhà phát triển phần mềm. Kiểm thử đơn vị tham số hóa đang dần đóng một vài trò hết sức quan trọng trong phát triển phần mềm. Khóa luận này ra đời chính là để nghiên cứu về phương pháp kiểm thửmới này và ứng dụng nó cho mục đích kiểm thử các chương trình Java. Nội dung khóa luận tập trung vào việc áp dụng khả năng của một nền kiểm chứng Java bytecode m ã nguồn mở rất hiệu quả và phổ biến hiện nay là Java PathFinder để xây dựng một hệ thống hỗ trợ kiểm thử đơn vị tham số hóa cho mục đích kiểm thử các chương trình Java. Kết quả của khóa luận là đã xây dựng được một hệ thống để thực thi các ca kiểm thử đơn vị tham số hóa viết cho các chương trình Java đơn giản. Bên cạnh đó, khóa luận cũng đã trình bày một cách sâu sắc về kiểm thử đơn vị tham số hóa và những kỹ thuật phức tạp đằng sau phươngpháp kiểm thử mới này cũng như một số nghiên cứu liên quan. Qua đó khóa luận kết thúc bằng việc phác thảo một số hướng có thể phát triển tiếp để hệ thốngnày xử lý được các kiểu dữ liệu phức tạp hơn.

pdf69 trang | Chia sẻ: nhungnt | Lượt xem: 2175 | Lượt tải: 2download
Bạn đang xem trước 20 trang tài liệu Đề tài Sinh ca kiểm thử tham số hóa cho chương trình Java, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
ĐẠI HỌC QUỐC GIA HÀ NỘI TRƯỜNG ĐẠI HỌC CÔNG NGHỆ Trần Bình Dương SINH CA KIỂM THỬ THAM SỐ HÓA CHO CHƯƠNG TRÌNH JAVA 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 - 2009 ĐẠI HỌC QUỐC GIA HÀ NỘI TRƯỜNG ĐẠI HỌC CÔNG NGHỆ Trần Bình Dương SINH CA KIỂM THỬ THAM SỐ HÓA CHO CHƯƠNG TRÌNH JAVA KHÓA LUẬN TỐT NGHIỆP ĐẠI HỌC HỆ CHÍNH QUY Ngành: Công Nghệ Thông Tin Cán bộ hướng dẫn: TS. Trương Anh Hoàng i LỜI CẢM ƠN Lời đầu tiên em xin được gửi lời cảm ơn chân thành tới TS. Trương Anh Hoàng, người thầy đáng kính đã tận tình hướng dẫn em trong suốt thời gian thực hiện khóa luận này. Em cũng muốn bày tỏ lòng biết ơn đến các thầy cô giáo trường Đại học Công Nghệ - Đại học Quốc Gia Hà nội, đặc biệt là các thầy cô trong khoa công nghệ thông tin đã tận tình dạy dỗ và tạo mọi điều kiện học tập thuận lợi cho em trong suốt bốn năm học qua. Cuối cùng, em xin gửi lời cảm ơn tới gia đình đình em. Nếu không có tình yêu, sự ủng hộ và động viên từ gia đình thì em sẽ không thể hoàn thành khoá luận và có được những kết quả như ngày hôm nay. Hà nội, 05/2009 Sinh viên Trần Bình Dương ii TÓM TẮT NỘI DUNG Kiểm thử đơn vị tham số hóa còn đang là một khái niệm mới mẻ đối với nhiều nhà phát triển phần mềm. Kiểm thử đơn vị tham số hóa đang dần đóng một vài trò hết sức quan trọng trong phát triển phần mềm. Khóa luận này ra đời chính là để nghiên cứu về phương pháp kiểm thử mới này và ứng dụng nó cho mục đích kiểm thử các chương trình Java. Nội dung khóa luận tập trung vào việc áp dụng khả năng của một nền kiểm chứng Java bytecode mã nguồn mở rất hiệu quả và phổ biến hiện nay là Java PathFinder để xây dựng một hệ thống hỗ trợ kiểm thử đơn vị tham số hóa cho mục đích kiểm thử các chương trình Java. Kết quả của khóa luận là đã xây dựng được một hệ thống để thực thi các ca kiểm thử đơn vị tham số hóa viết cho các chương trình Java đơn giản. Bên cạnh đó, khóa luận cũng đã trình bày một cách sâu sắc về kiểm thử đơn vị tham số hóa và những kỹ thuật phức tạp đằng sau phương pháp kiểm thử mới này cũng như một số nghiên cứu liên quan. Qua đó khóa luận kết thúc bằng việc phác thảo một số hướng có thể phát triển tiếp để hệ thống này xử lý được các kiểu dữ liệu phức tạp hơn. iii MỤC LỤC LỜI CẢM ƠN .....................................................................................................................i TÓM TẮT NỘI DUNG.....................................................................................................ii MỤC LỤC..........................................................................................................................iii CÁC KÝ HIỆU VIẾT TẮT .............................................................................................v DANH MỤC HÌNH VẼ ...................................................................................................vi Chương 1: Kiểm thử đơn vị tham số hóa ......................................................................3 1.1. Kiểm thử phần mềm .................................................................................................3 1.2. Kiểm thử đơn vị........................................................................................................4 1.3. Kiểm thử đơn vị tham số hóa...................................................................................6 1.3.1. Khái niệm...........................................................................................................6 1.3.2. Mối quan hệ giữa UT và PUT ..........................................................................7 1.3.3. Kiểm thử đơn vị tham số hóa với Pex ..............................................................8 1.3.4. Các mẫu kiểm thử tham số hóa ........................................................................9 1.3.5. Lựa chọn đầu vào kiểm thử với Pex...............................................................10 Chương 2: Sinh dữ liệu kiểm thử tự động cho PUT ..................................................12 2.1. Thực thi tượng trưng ..............................................................................................13 2.1.1. Những khái niệm cơ bản .................................................................................13 2.1.2. Thực thi tượng trưng tĩnh................................................................................14 2.1.3. Thực thi tượng trưng động ..............................................................................17 2.2. Xây dựng ràng buộc ...............................................................................................23 2.2.1. Lưu trữ giá trị tượng trưng..............................................................................24 2.2.2. SE với các kiểu dữ liệu nguyên thủy..............................................................25 2.2.3. SE với đối tượng..............................................................................................28 2.2.4. SE với các lời gọi phương thức ......................................................................30 2.3. Sinh dữ liệu kiểm thử cho PUT .............................................................................31 Chương 3: Sinh ca kiểm thử tham số hóa với JPF.....................................................36 3.1. Kiến trúc của JPF ...................................................................................................36 3.2. Symbolic JPF..........................................................................................................40 3.2.1. Bộ tạo chỉ thị....................................................................................................40 3.2.2. Các thuộc tính ..................................................................................................41 3.2.3. Xử lý các điều kiện rẽ nhánh ..........................................................................42 3.2.4. Ví dụ.................................................................................................................43 3.2.5. Kết hợp thực thi cụ thể và thực thi tượng trưng ............................................47 iv 3.3. Sinh PUT với Symbolic JPF ..................................................................................48 3.4. Mở rộng Symbolic JPF ..........................................................................................53 3.4.1. Các phương pháp cũ........................................................................................53 3.4.2. Hướng mở rộng ...............................................................................................54 KẾT LUẬN.......................................................................................................................58 TÀI LIỆU THAM KHẢO ................................................................................................1 v CÁC KÝ HIỆU VIẾT TẮT CFG Control Flow Graph DSE Dynamic Symbolic Execution JPF Java PathFinder PC Path Condition PUT Parameterized Unit Test SE Symbolic Execution SET Symbolic Execution Tree TIS Test Input Selector UT Unit Test vi DANH MỤC HÌNH VẼ Hình 1: Mối quan hệ giữa UT và PUT...............................................................................8 Hình 2 : Cây thực thi tượng trưng ....................................................................................16 Hình 3: Cây thực thi tượng trưng được quản lý riêng.....................................................22 Hình 4 : Hệ thống kiểm thử tổng quát..............................................................................24 Hình 5: Gán giá trị tượng trưng cho tham số đầu vào.....................................................26 Hình 6: Thực thi tượng trưng với câu lệnh gán ...............................................................27 Hình 7: Thực thi tượng trưng với câu lệnh rẽ nhánh.......................................................28 Hình 8: Khởi tạo đối tượng làm đầu vào cho chương trình............................................29 Hình 9. Sinh ra các ràng buộc liên quan tới đối tượng ...................................................30 Hình 10: Thuật toán sinh dữ liễu kiểm thử ......................................................................32 Hình 11: Các cây thực thi cục bộ tương ứng với hàm abs và TestAbs ..........................34 Hình 12: Kiến trúc JPF......................................................................................................37 Hình 13: Bộ sinh lựa chọn trong JPF ...............................................................................39 Hình 14. Bộ tạo chỉ thị trong JPF .....................................................................................40 Hình 15. Trạng thái chương trình thực thi trong Symbolic JPF .....................................41 Hình 16: Bùng nổ việc thực thi tượng trưng trong Symbolic JPF..................................48 Hình 17: Kiến trúc hệ thống cài đặt .................................................................................49 Hình 18. Một ví dụ với hệ thống cài đặt ..........................................................................52 1 MỞ ĐẦU Trong nền kinh tế hiện nay, ngành công nghiệp phần mềm giữ vai trò hết sức quan trọng. Với một số nước có nền công nghệ thông tin phát triển thì ngành công nghiệp phần mềm có khả năng chi phối cả nền kinh tế. Tuy nhiên để đảm bảo chất lượng cho các phần mềm là một thách thức không nhỏ trong ngành công nghiệp phần mềm. Việc phát hiện và khắc phục các lỗi cho các phần mềm là một công việc đòi hỏi nhiều nỗ lực và chi phí trong phát triển phần mềm. Với những lĩnh vực ứng dụng ngày càng mở rộng của phần mềm hiện nay thì chất lượng phần mềm càng được quan tâm hàng đầu. Trong kỹ nghệ phần mềm thì kiểm thử chính là phương pháp dùng để phát hiện các lỗi của phần mềm. Trong đó kiểm thử đơn vị là giai đoạn đầu tiên trong quy trình kiểm thử. Kiểm thử đơn vị là một công việc bắt buộc trong phát triển phần mềm. Theo nghiên cứu của Micorosoft thì có tới 79% các nhà phát triển phần mềm phải viết các ca kiểm thử đơn vị để thực hiện việc kiểm thử phần mềm mức đơn vị. Rõ ràng kiểm thử đơn vị là một công việc nặng nhọc làm mất nhiều thời gian và chi phí trong phát triển phần mềm. Do đó có một phương pháp kiểm thử đơn vị mới đã ra đời giúp cải thiện phương pháp kiểm thử đơn vị truyền thống đó là kiểm thử đơn vị tham số hóa. Với kiểm thử đơn vị tham số hóa công sức giành cho việc kiểm thử phần mềm mức đơn vị đã được giảm đi đáng kể. Kiểm thử đơn vị tham số hóa giúp việc phát hiện các lỗi của phần mềm đạt hiệu quả cao hơn do đó nâng cao chất lượng của phần mềm. Kiểm thử đơn vị tham số hóa còn là một phương pháp kiểm thử đơn vị còn rất mới và nó mới chỉ được áp dụng trong môi trường .NET. Vì vậy việc nghiên cứu về kiểm thử đơn vị tham số hóa và ứng dụng nó là một nhu cầu cấp bách. Và khóa luận này ra đời chính là vì mục đích này. Nội dụng chính của khóa luận gồm 3 chương: Chương 1: Trình bày tổng quan về kiểm thử và làm rõ bản chất của kiểm thử đơn vị tham số hóa thông qua công cụ Pex của Microsoft. Chương 2: Nghiên cứu về phương pháp sinh dữ liệu làm đầu vào kiểm thử cho các ca kiểm thử đơn vị tham số hóa. Trong chương này ta cũng sẽ trình bày về một hệ thống kiểm thử tổng quát nhất dùng để thực thi các ca kiểm thử đơn vị tham số hóa viết cho ngôn ngữ Java. 2 Chương 3: Trong chương này ta sẽ nghiên cứu về một nền (framework) kiểm chứng Java bytecode mã nguồn mở rất phổ biến hiện nay đó là Java PathFinder và áp dụng khả năng của nó để xây dựng một nền thực thi các ca kiểm thử tham số hóa viết cho những chương trình Java đơn giản. Đồng thời ta cũng đề xuất giải pháp để có thể mở rộng Java PathFinder cho mục đích hoàn thiện nền kiểm thử mà ta đã xây dựng. 3 Chương 1: Kiểm thử đơn vị tham số hóa 1.1. Kiểm thử phần mềm Để đả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 đem chúng vào 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 tra mô hình (model checking)[4], các kỹ thuật phân tích tĩnh (static analysis)[24] và kiểm thử (software testing)[1]. 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. Trong kiểm tra 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 tra 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ể. Kiểm tra mô hình phân tích hết mọi khía cạnh thực thi của chương trình và chỉ ra những sự vi phạm nhưng không chứng minh được chương trình sẽ được thực thi chính xác mà không có lỗi. Hạn chế của kiểm tra mô hình đó là không gian trạng thái của mô hình thường quá lớn do đó việc thám hiểm tất cả các trạng thái không phải lúc nào cũng thực hiện được. 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í già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 quy trình kiểm thử đó. Có các kỹ thuật kiểm thử khác nhau được sử dụng như kiểm thử hộp trắng (white-box testing), kiểm thử hộp đen (black-box testing), kiểm thử hộp xám (gray-box testing). Các kỹ thuật kiểm thử đó được dựa trên 2 loại kiểm thử đó là kiểm thử chức năng (funcional testing) và kiểm thử cấu trúc (structured testing). Kiểm thử chức năng là loại kiểm thử dựa trên đặc tả chức năng của hệ thống, nó phát hiện các sai sót về chức năng mà không quan tâm tới cài đặt. 4 Kiểm thử cấu trúc là loại kiểm thử có nghiên cứu mã nguồn bằng việc phân tích thứ tự thực hiện các lệnh. 1.2. Kiểm thử đơn vị Kiểm thử đơn vị là một cộng việc quan trọng trong kỹ nghệ phần mềm. Kiểm thử đơn vị thường được áp dụng để kiểm tra việc cài đặt của các lớp hoặc phương thức. Để thực hiện việc kiểm thử đơn vị, các lớp kiểm thử được tạo ra. Các lớp kiểm thử này gồm các phương thức kiểm thử. Các phương thức kiểm thử là các phương thức không tham số có kiểu trả về là void chứa trong các lớp kiểm thử để kiểm tra các khía cạnh cài đặt khác nhau của chương trình. Mỗi phương thức kiểm thử trong các lớp kiểm thử biểu thị cho một ca kiểm thử đơn vị (UT). Có thể chia một phương thức kiểm thử ra làm 3 phần: Các giá trị đầu vào, dãy các lời gọi phương thức, và sự xác nhận (assertions). Kiểm thử thất bại nếu bất cứ sự xác nhận nào bị vị phạm hoặc có một ngoại lệ (exception) xảy ra. Ví dụ 1.1: Ta xét một phương thức kiểm thử được viết trong nền kiểm thử VSUnit. public void TestArrayList() { // exemplary data int capacity = 1; object element = null; // method sequence ArrayList list = new ArrayList(capacity); list.Add(element); // assertions Assert.IsTrue(list[0] == element); } Phương thức kiểm thử TestArrayList bắt đầu bằng việc gán giá trị 1 cho biến capacity và giá trị null cho biến element như là các giá trị đầu vào kiểm thử. Sau đó nó thực hiện một dãy các lời gọi phương thức, trước tiên là khởi tạo một đối tượng ArrayList với kích cỡ là capacity không chứa phần tử nào. ArrayList là một mảng động với kích cỡ có thể thay đổi. Tiếp theo nó chèn một đối tượng là element vào mảng. Và cuối cùng là xác nhận xem phần tử đầu tiên của mảng có bằng đối tượng vừa được chèn vào hay không. Việc cài đặt nhiều phương thức kiểm thử không đảm bảo rằng sẽ kiểm tra được hết mọi khía cạnh thực thi của chương trình. Với các chương trình có nhiều đường đi thực thi khác nhau thì việc thiếu xót các UT để kiểm tra một vài đường đi thực thi trong chương trình là điều thường xuyên xảy ra. Khi người lập trình thay đổi mã cài đặt của chương trình được kiểm thử thì nếu như các phương thức kiểm thử không được 5 cập nhật theo thì sẽ dẫn đến việc nhiều đường đi thực thi của chương trình sẽ không được kiểm thử. Các nền kiểm thử hỗ trợ viết các UT theo các cách khác nhau. Tuy nhiên, đa phần các nền kiểm thử đều cung cấp những dịch vụ (service) như sau: + Cung cấp thuộc tính để chỉ định các phương thức như là các UT. + Phát hiện và thực thi tự động các UT + Một runner với khả năng báo cáo (reporting). Một runner có thể là ứng dụng dòng lệnh (console) hoặc là giao diện tích hợp. Như trong nền kiểm VSUnit[29] cho môi trường .NET. Ta sử dụng thuộc tính [TestClass] để chỉ định một lớp là lớp kiểm thử, và [TestMethod] để chỉ định một phương thức như là một phương thức kiểm thử. Ngoài ra còn có các thuộc tính khác như [ExpectedException] để chỉ định phương thức kiểm thử ném ra ngoại lệ của một kiểu ngoại lệ cụ thể nào đó. Ví dụ 1.2: Giả sử có một lớp LuhnAlgorithm được cài đặt như sau: public static class LuhnAlgorithm { public static bool Validate(string number){ if (number == null) throw new ArgumentNullException(""); foreach (var c in number) if (!Char.IsDigit(c)) throw new ArgumentException(""); return false; } } Ta có thể viết một lớp kiểm thử chứa các UT để thực hiện việc kiểm thử lớp LuhnAlgorithm: [TestClass]// lớp chứa các unit test public class LuhnAlgorithmTest { [TestMethod] [ExpectedException(typeof(ArgumentNullException))] public void Test1() { LuhnAlgorithm.Validate(null); } [TestMethod] [ExpectedException(typeof(ArgumentException))] public void Test2() { LuhnAlgorithm.Validate("K50"); } 6 [TestMethod] public void Test3() { LuhnAlgorithm.Validate(“123”); } } Khi thực thi phương thức kiểm thử Test1 thì ngoại lệ ArgumentNullException được ném ra. Khi thực thi phương thức kiểm thử Test2 thì ArgumentException được ném ra. Rõ ràng là mỗi phương thức kiểm thử ở trên chỉ có thể kiểm tra việc thực thi của lớp LuhnAlgorithm theo một nhánh đi cụ thể. Thực thi cả 3 phương thức kiểm thử ở trên ta sẽ kiểm tra được tất cả các trường hợp thực thi của lớp LuhnAlgorithm. Với một chương trình có nhiều đường đi thì ta cần viết các UT khác nhau để kiểm tra sự thực thi của chương trình theo các đường đi đó. Tuy nhiên, với những chương trình có nhiều đường đi thực thi khác nhau thì việc viết các UT như thế đòi hỏi nhiều thời gian và công sức để tính các giá trị đầu vào thích hợp và khó có thể kiểm tra hết được sự thực thi của chương trình theo tất cả các đường đi. 1.3. Kiểm thử đơn vị tham số hóa Có rất nhiều các nền kiểm thử khác nhau như JUnit[33] cho Java, NUnit[34], VSUnit[29] cho .NET để thực thi các ca kiểm thử đơn vị. Tuy nhiên các nền kiểm thử này không hỗ trợ việc sinh tự động các ca kiểm thử đơn vị. Việc viết các ca kiểm thử đơn vị để thực thi tất cả các đường đi của một chương trình là một công việc nặng nhọc. Giải pháp để giảm công sức cho việc này đó là sử dụng ca kiểm thử đơn vị tham số hóa. Kiểm thử đơn vị tham số hóa[7, 11, 12] là phương pháp mới trong kiểm thử phần mềm. Kiểm thử đơn vị tham số hóa giúp cải thiện nỗ lực trong việc phát triển phần mềm. Về bản chất nó chính là sự mở rộng của phương pháp kiểm thử đơn vị truyền thống. 1.3.1. Khái niệm Các UT truyền thống là các phương thức kiểm thử không tham số. Ta có thể mở rộng các UT đó bằng cách cho phép truyền vào tham số cho các phương thức kiểm thử. Các ca kiểm thử tham số hóa (PUT) là sự mở rộng của