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.
69 trang |
Chia sẻ: nhungnt | Lượt xem: 2258 | Lượt tải: 2
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