1. Trang chủ
  2. » Luận Văn - Báo Cáo

SINH CA KIỂM THỬ THAM SỐ HÓA CHO CHƯƠNG TRÌNH JAVA

69 598 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Sinh Ca Kiểm Thử Tham Số Hóa Cho Chương Trình Java
Tác giả Trần Bình Dương
Người hướng dẫn TS. Trương Anh Hoàng
Trường học Đại Học Quốc Gia Hà Nội - Trường Đại Học Công Nghệ
Chuyên ngành Công Nghệ Thông Tin
Thể loại Khóa luận tốt nghiệp
Năm xuất bản 2009
Thành phố Hà Nội
Định dạng
Số trang 69
Dung lượng 1,13 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

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.

Trang 1

ĐẠI HỌC QUỐC GIA HÀ NỘI TRƯỜNG ĐẠI HỌC CÔNG NGHỆ

Trang 2

ĐẠI HỌC QUỐC GIA HÀ NỘI TRƯỜNG ĐẠI HỌC CÔNG NGHỆ

Ngành: Công Nghệ Thông Tin

Cán bộ hướng dẫn: TS Trương Anh Hoàng

Trang 3

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óaluậ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ôngNghệ - Đại học Quốc Gia Hà nội, đặc biệt là các thầy cô trong khoa công nghệ thôngtin đã 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ốnnă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

Trang 4

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ềunhà 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ếtsứ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êncứ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ácchươ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ộtnền kiểm chứng Java bytecode mã nguồn mở rất hiệu quả và phổ biến hiện nay là JavaPathFinder để 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àycũ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ảomộ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ứctạp hơn

Trang 5

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 iv

DANH MỤC HÌNH VẼ v

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

Trang 6

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

Trang 7

CÁC KÝ HIỆU VIẾT TẮT

Trang 8

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

Trang 9

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ứcquan 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ôngnghiệp phần mềm có khả năng chi phối cả nền kinh tế Tuy nhiên để đảm bảo chấtlượ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ầnmề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ỏinhiề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àycà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âmhàng đầu Trong kỹ nghệ phần mềm thì kiểm thử chính là phương pháp dùng để pháthiệ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 quytrì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ếtcá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àngkiể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í trongphá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úpcả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ềmmứ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ệncá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 đờichí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ử chocá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óaviết cho ngôn ngữ Java

Trang 10

Chương 3: Trong chương này ta sẽ nghiên cứu về một nền (framework) kiểmchứng Java bytecode mã nguồn mở rất phổ biến hiện nay đó là Java PathFinder và ápdụ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ếtcho 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

Trang 11

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àmviệ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ácphầ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ọngkhá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ươngphá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 (modelchecking)[4], các kỹ thuật phân tích tĩnh (static analysis)[24] và kiểm thử (softwaretesting)[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 racá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íchmộ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 trongtấ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ủachươ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ônggian 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áikhô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ắcphụ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ànhcho việc kiểm thử chiếm khoảng 50% tổng chi phí trong phát triển phần mềm Kiểmthử 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-boxtesting), 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ăngcủ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

Trang 12

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àygồ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ôngtham 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ạnhcà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ãycá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() {

}

Phương thức kiểm thử TestArrayList bắt đầu bằng việc gán giá trị 1 cho biếncapacity 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ượngArrayList 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àomả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 đượchế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 đithự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 thitrong 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

Trang 13

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, đaphầ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

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ớpLuhnAlgorithm:

[TestClass]// lớp chứa các unit test

public class LuhnAlgorithmTest {

[ExpectedException(typeof(ArgumentException))]

public void Test2() {

LuhnAlgorithm.Validate("K50");

}

Trang 14

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 đượcné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 thicủ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ớimộ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ặngnhọ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ầnmề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ầnmề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ềnthố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ểmthử Các ca kiểm thử tham số hóa (PUT) là sự mở rộng của các UT truyền thống CácPUT là các phương thức kiểm thử cho phép nhận các giá trị đầu vào kiểm thử khácnhau thông qua tham số đầu vào

Trang 15

PUT được hiểu ở 2 khía cạnh:

+ PUT là sự đặc tả về hành vi bên ngoài của chương trình Nếu như mỗi UT kiểmtra sự thực thi của chương trình với những giá trị đầu vào được chọn trước và xác nhậnkết quả của lần thực thi đó có như mong đợi Nói cách khác, mỗi UT biểu thị cho mộthành vi thực thi cụ thể của chương trình UT chỉ cung cấp các giá trị đầu vào cụ thểcho chương trình và xác nhận kết quả thực thi của chương trình với những đầu vào cụthể đó mà không quan tâm tới quá trình thực thi của chương trình với những giá trị đódiễn ra như thế nào Vì thế, UT biểu thị cho hành vi bên ngoài của chương trình PUTcũng xác nhận về hành vị thực thi của chương trình nhưng được mở rộng cho tất cảcác giá trị đầu vào có thể Sự xác nhận (assertion) của PUT biểu thị cho các hành vibên ngoài của chương trình Ở khía cạnh này, PUT giống như sự đặc tả hộp đen(black-box) cho lớp được PUT kiểm thử

+ Sự lựa chọn các đầu vào kiểm thử cho PUT dẫn đến việc phân tích chươngtrình được kiểm thử Việc phân tích này cần tìm ra các giá trị sao cho khi chương trìnhđược thực thi với các giá trị đó thì có nhiều dòng lệnh được chạy (code coverage)[5].Nói cách khác, các giá trị cần được lựa chọn sao cho PUT có thể kiểm tra được cácđường đi thực thi khác nhau của chương trình Và mỗi UT có thể được sinh ra từ PUTbằng cách gọi PUT với mỗi đầu vào cụ thể được chọn Ở khía cạnh này, PUT là kiểmthử hộp trắng (white-box)

Từ đặc tả về PUT, ta có thể phát biểu vấn đề kiểm thử như sau:

Cho một chương trình P gồm các câu lệnh S, cần tính toán một tập hợp các đầuvào (inputs) I sao cho với tất cả các câu lệnh cần thực thi s trong S, tồn tại đầu vào itrong I để P(i) thực thi s

1.3.2 Mối quan hệ giữa UT và PUT

Với mỗi chương trình có mã nguồn ta có thể viết các PUT để mô tả các hành vithực thi của nó Tuy nhiên, nếu đã có các UT được viết thì ta có thể tái cấu trúc mã càiđặt các UT đó để biến chúng thành các PUT Ngược lại, từ các PUT ta có thể sinh lạicác UT bằng cách truyền các giá trị cụ thể làm đầu vào cho PUT Các nền kiểm thửđơn vị khác nhau hỗ trợ viết các UT theo các cách khác nhau Do đó các PUT cũngcần được viết sao cho có thể sinh ra các UT tương ứng với các nền kiểm thử đó

Trang 16

Hình 1: Mối quan hệ giữa UT và PUT

1.3.3 Kiểm thử đơn vị tham số hóa với Pex

Pex[30] là công cụ mạnh mẽ hỗ trợ việc viết và thực thi các ca kiểm thử tham sốhóa cho môi trường NET

Ví dụ 1.3: Ca kiểm thử tham số hóa sử dụng Pex :

Cũng như với UT, ta có thể viết các lớp kiểm thử chứa các ca kiểm thử tham sốhóa Với sự hỗ trợ của Pex ta có thể thực thi các ca kiểm thử tham số hóa đó Tuynhiên không giống việc thực thi các lớp kiểm thử chứa các UT, Pex chỉ thực thi đượcmột ca kiểm thử tham số hóa trong mỗi lần chạy

[PexMethod] // exemplary data

public void PutArrayList(ArrayList list, object element) {

}

Ca kiểm thử tham số hóa ở trên là sự mở rộng của UT trong ví dụ 1.1 Rõ ràngcác giá trị đầu vào của UT trong ví dụ 1.1 là các giá trị cụ thể đã được chuyển thànhcác tham số đầu vào của phương thức Nếu như UT trong ví dụ 1.1 kiểm thử phươngthức Add của lớp ArrayList ở khía cạnh là khi chèn một đối tượng có giá trị null vàomột ArrayList rỗng thì đối tượng được chèn vào trở thành phần tử đầu tiên củaArrayList Thì với ca kiểm thử tham số hóa ở trên phương thức Add được kiểm thửvới những đối tượng và ArrayList khác Các ArrayList làm đầu vào kiểm thử có thể làArrayList không chứa phần tử nào hoặc ArrayList đã chứa một số phần tử, hoặcArrayList đã chứa đủ số phần tử so với kích cỡ được cấp phát thì khi chèn một đốitượng object có giá trị là null hay các giá trị khác thì đối tượng được chèn vào trởthành phần tử cuối cùng của ArrayList

Trang 17

PUT có thể sử dụng các giả thuyết (assumptions) để giảm kích cỡ miền giá trịcủa tham số đầu vào Các tham số đầu vào có giá trị thỏa mãn giả thuyết này mới đượcxem xét làm đầu vào kiểm thử Như với PUT ở trên thì chỉ các ArrayList khác nullmới được lựa chọn làm đầu vào kiểm thử.

Khi Pex thực thi ca kiểm thử tham số hóa ở trên sẽ sinh ra Test Suite gồm 2VSUnit UT Đồng thời Pex cũng báo cáo về kết quả xác nhận của ca kiểm thử tham sốhóa ở trên

[TestMethod]

public void TestAddNoOverflow() {

PutArrayList(new ArrayList(1), new object());

}

[TestMethod]

public void TestAddWithOverflow() {

PutArrayList(new ArrayList(0), new object());

là ca kiểm thử tham số hóa Ta muốn viết một lớp kiểm thử chứa các ca kiểm thử tham

số hóa cần sử dụng thuộc tính [PexClass] và [PexMethod] để viết các ca kiểm thửtham số hóa

1.3.4 Các mẫu kiểm thử tham số hóa

Viết các ca kiểm thử tham số hóa là một nghệ thuật Để viết các ca kiểm thử tham sốhóa hiệu quả, ta cần thực sự hiểu về mã cài đặt của chương trình mà ta muốn kiểm thử.Pex hỗ trợ nhiều mẫu kiểm thử tham số hóa khác nhau[15] Các mẫu được sử dụngnhiều nhất đó là mẫu AAA (Triple-A) và AAAA:

+ Với mẫu AAA (Arrange, Act, Assert) PUT được tổ chức thành 3 phần:

 Arrange: khởi tạo giá trị các biến sẽ sử dụng

 Act: dãy các lời gọi phương thức

 Assert: sự xác nhận+ Với mẫu AAAA, một giả thuyết (Assume) được thêm vào để giới hạn miềngiá trị của các tham số đầu vào

Trang 18

Ví dụ 1.4: Mẫu kiểm thử tham số hóa AAAA

[PexMethod]

void AssumeActAssert(ArrayList list, object item) {

// assume PexAssume.IsNotNull(list);

// arrange

var count = list.Count;

// act list.Add(item);

// assert Assert.IsTrue(list.Count == count + 1);

}

1.3.5 Lựa chọn đầu vào kiểm thử với Pex

Thêm tham số vào UT cải thiện đặc tả về hành vi mong muốn nhưng lại mất đicác ca kiểm thử cụ thể Ta cần những giá trị thực sự cho các tham số đầu vào để sinhlại các ca kiểm thử cụ thể PUT sẽ không thể thực thi nếu không có các giá trị cụ thểđược truyền vào cho các tham số đầu vào của PUT

Để có thể sinh các đầu vào cụ thể cho PUT Pex cần phải phân tích chương trình

mà PUT kiểm thử Có 2 kỹ thuật phân tích chương trình đó là phân tích tĩnh và phântích động:

+ Phân tích tĩnh (static analysis): Kiểm chứng một tính chất nào đó của chươngtrình bằng việc phân tích tất cả các đường đi thực thi Kỹ thuật này coi các cảnh bảo(violations) là các lỗi (error)

+ Phân tích động (dynamic analysis): Kiểm chứng một tính chất bằng việc phântích một số đường đi thực thi Đây là một kỹ thuật phân tích động hỗ trợ việc phát hiện

ra các lỗi (bugs) nhưng không khẳng định được rằng có còn những lỗi khác hay không.Các kỹ thuật này thường không tìm ra được tất cả các lỗi

Pex cài đặt một kỹ thuật phân tích chương trình bằng cách kết hợp cả hai kỹ thuậtphân tích chương trình ở trên gọi là thực thi tượng trưng động[14, 25] Về bản chấtPex là một công cụ hỗ trợ kỹ thuật kiểm thử hộp trắng (white-box testing) Tương tựnhư kỹ thuật phân tích chương trình tĩnh, Pex chứng minh được rằng một tính chấtđược kiểm chứng trong tất cả các đường đi khả thi Pex chỉ báo cáo (reporting) về cáclỗi thực sự như với kỹ thuật phân tích chương trình động

Trang 19

Pex sử dụng khả năng của bộ xử lý ràng buộc Z3[31] kết hợp với các lý thuyếttoán học khác như hàm chưa định nghĩa, lý thuyết mảng, bit-vetor[2] để giải quyếtràng buộc sinh ra trong quá trình thực thi tượng trưng động và sinh ra các đầu vàokiểm thử cụ thể cho PUT

Trang 20

Chương 2: Sinh dữ liệu kiểm thử tự động cho PUT

Trong kiểm thử phần mềm, các ca kiểm thử thường được tạo ra thủ công do đógây tốn kém trong chi phí phát triển phần mềm và làm kéo dài thời gian để hoàn thànhmột phần mềm

Có các phương pháp khác nhau hỗ trợ việc sinh tự động các ca kiểm thử mộtcách có hệ thống giúp giảm chi phí cho việc kiểm thử phần mềm Một trong nhữngphương pháp đơn giản nhất để sinh tự động các ca kiểm thử đó là kiểm thử ngẫu nhiên(random testing)[5] Với kiểm thử ngẫu nhiên các đầu vào cho hệ thống được sinhngẫu nhiên Để thực hiện, một luồng các bits được sinh ngẫu nhiên để thể hiện cho cácgiá trị của tham số đầu vào Giả sử với một hàm nhận tham số đầu vào có kiểu stringthì chỉ cần sinh ngẫu nhiên một luồng các bits để thể hiện giá trị cho một chuỗi Kiểmthử ngẫu nhiên có ưu điểm là dễ dàng sinh các đầu vào ngẫu nhiên và hệ thống kiểmthử ngẫu nhiên không yêu cầu nhiều tài nguyên bộ nhớ lúc thực thi Nhưng hạn chếcủa nó là kiểm tra cùng một hành vị thực thi của chương trình nhiều lần với những đầuvào khác nhau và chỉ có thể kiểm tra được một số trường hợp thực thi của chươngtrình Thêm vào đó, kiểm thử ngẫu nhiên khó xác định được khi nào việc kiểm thử nênđược dừng lại và nó không biết tại điểm nào không gian trạng thái đã được thám hiểmhết Để xác định khi nào việc kiểm thử dừng lại thì hệ thống kiểm thử ngẫu nhiên đượckết hợp với các adequacy criterion [5] Giả sử adequacy criterion là bao phủ lệnh

(statement coverage)[5] thì việc kiểm thử chỉ dừng lại khi tất cả các câu lệnh của

chương trình được thực thi ít nhất một lần

Một phương pháp khác đang rất phổ biến giúp khắc phục được hạn chế của kiểmthử ngẫu nhiên đó là thực thi tượng trưng[6] Thực thi tượng trưng chính là việc xâydựng các ràng buộc dựa vào các giá trị tượng trưng và giải quyết các ràng buộc đó đểsinh ra các giá trị làm đầu vào chương trình mà có thể thực thi chương trình theo cácđường đi thực thi khác nhau Ý tưởng chính của thực thi tượng trưng đó là thực thi mộtchương trình với những giá trị tượng trưng Có hai cách tiếp cận đối với thực thi tượngtrưng đó là cách tiếp cận dựa trên phân tích tĩnh và phân tích động chương trình Việc lựa chọn các đầu vào kiểm thử cho PUT liên quan tới vấn đề sinh dữ liệukiểm thử tự động Sinh dữ liệu kiểm thử tự động là một lĩnh vực nghiên cứu rất rộngtrong kiểm thử phần mềm Có rất nhiều các kỹ thuật khác nhau[8, 10, 18] được sửdụng để sinh dữ liệu kiểm thử tự động Tuy nhiên với PUT thì các dữ liệu làm đầu vàokiểm thử cần được chọn lựa làm sao để PUT có thể kiểm tra được sự thực thi của

Trang 21

chương trình theo tất cả các đường đi có thể Hơn nữa số lượng các đầu vào kiểm thửcho PUT là tối thiểu Việc sinh dữ liệu để có thể kiểm tra được sự thực thi một chươngtrình theo tất cả các đường đi có thể với các dữ liệu đó là một vấn đề phức tạp vàkhông phải lúc nào cũng thực hiện được trên thực tế Thực chất của vấn đề sinh dữ liệukiểm thử tự động cho PUT là việc xây dựng ràng buộc và xử lý ràng buộc Các ràngbuộc được xây dựng sao cho chúng có thể biểu thị cho các đường đi thực thi trong mộtchương trình Và giải quyết các ràng buộc đó sẽ sinh ra các dữ liệu mà chương trình cóthể thực thi với các dữ liệu đó để đi theo các đường đi khác nhau trong chương trình.

2.1 Thực thi tượng trưng

2.1.1 Những khái niệm cơ bản

Một chương trình P có thể xem xét như một hàm, P : S→ R , trong đó S là tậphợ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ể đượcbiể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ểuthứ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) đitheo đườ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ếtthú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ằngviệ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ừ

Trang 22

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ộtdã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ãybao gồm n câu lệnh đầu tiên của p

Do đó việc sinh dữ liệu kiểm thử cho PUT 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 PUT kiểm thử

2.1.2 Thực thi tượng trưng tĩnh

Ý tưởng chính của thực thi tượng trưng (SE)[6] là thực thi chương trình với cácgiá trị tượng trưng (symbolic values) thay vì các giá trị cụ thể (concrete values) củacác tham số đầu vào

Với mỗi tham số đầu vào một giá trị tượng 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 tượng trưng một giá trị tượng trưng sẽ được tínhtoán để kết hợp cùng với nó Mỗi giá trị tượng 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ộtchươ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ủacác giá trị tượng trưng

Giá trị tượng trưng của biến x có thể được biểu thị bởi:

(a) Một ký hiệu đầu vào(input symbol)

(b) Một biểu thức kết hợp giữa các giá trị tượng trưng bởi các toán tử.(c) Một biểu thức kết hợp giữa giá trị tượng 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ị tượng trưng của một tham số đầu vào lúcbắ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ởicác ký hiệu đầu vào khác nhau Các toán tử (operator) 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ị tượng trưng nào được tính toán để kết hợp với nó Giá trị tượng trưng cuả cácbiế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ìnhthực thi Gán một giá trị cụ thể từ một biến tới biến khác dẫn đến giá trị tượng trưngcũng được sao chép nếu biến được gán tới một biến khác có một giá trị tượng trưng

Trang 23

Giả sử với một câu lệnh gán x=e, nếu e là một tham số đầu vào, thì giá trị tượng trưngđược gán cho x sẽ có dạng (a) Nếu e là một biểu thức tính toán gồm các toán hạng.Các toán hạng đó có thể là biến, tham số đầu vào hoặc hằng thì giá trị tượng trưng củabiến x sẽ là một biểu thức tượng trưng dạng (b) nếu mỗi toán hạng trong biểu thức cómột giá trị tượng trưng kết hợp với nó, hoặc là một biểu thức tượng trưng dạng (c) nếu

có toán hạng là hằng số hoặc không có giá trị tượng trưng kết hợp với nó Giá trị cụthể của một hằng hoặc một biến cũng được sử dụng trong biểu thức tượng trưng nếunhư hằng hoặc biến đó không có giá trị tượng trưng kết hợp với nó

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 (PC) và biến đếm chương trình(program counter) Biến đếm chương trình xác định chỉ thị (câu lệnh) tiếp theo sẽ đượcthự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àochươ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 tượng trưng dạng x o y trong đó x là giá trịtượng trưng, y là giá trị tượng trưng hoặc giá trị cụ thể và o  {≤, ≠, =, <, >, ≥} Cácrà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ềukiệ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ácrà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ịtượng trưng hay biểu thức của giá trị tượng trưng và giá trị cụ thể phụ thuộc vào biếnxuất hiện trong biểu thức điều kiện của câu lệnh rẽ nhánh có giá trị tượng trưng đượctính toán để kết hợp với nó hay không

Trong quá trình thực thi tượng 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áctham số đầu vào Tại các điểm rẽ nhánh, cả hai nhánh ra sẽ được xem xét để điềuhướ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âulệnh đó là câu lệnh gán (assignment statments) và câu lệnh rẽ nhánh Tại các câu lệnhgán thì giá trị tượng trư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ộcnà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ờicá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ả

Trang 24

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 tượng trưng một chương trình Một cây thực thi tượng trưng(SET) được đưa ra để biểu thị cho các đường đi thực thi trong quá trình thực thi tượngtrư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ựcthi tượng 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 sangtrạng thái khác

Trang 25

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ủanhá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 Swaptiế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 2 nhánh đi mới được xem xét để thực thi vớicác giá trị tượng 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ôngtồ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ệcthự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

2.1.3 Thực thi tượng trưng động

Thực thi tượng trưng động[14, 25] là kỹ thuật thực thi tương trưng dựa trên phântích chương trình động Thực thi tượng trưng động chính là sự kết hợp giữa thực thi cụthể và thực thi tượng trưng Trong thực thi tượng trưng động, chương trình được thựcthi 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 thichươ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àngbuộc đã thu gom được

Tạ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ánhnhậ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àngbuộ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 (Constraint Solver) sẽ được sử dụng để giảiquyế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

Trang 26

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 ứngvớ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ạicho 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ằngtất cả các đường đi phân tích được trong quá trình thực thi tượng trưng động đều là cácđường đi khả thi

Thuật toán 2.1: DSE

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 điC’(i): Điều kiện đường đi suy ra từ C(i)

Trang 27

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ựcthi và qua trình thực thi sẽ được dừng lại

Bảng 1: Ví dụ về thực thi tượng trưng động

Ràng buộc C’(i) Input i Ràng buộc được ghi nhớ C(i)

a!=null {} a!=null && !(a.length>0)a!=null&& a.length>0 {0} a!=null && a.length>0

&& a[0]!=123456789a!=null && a.length>0

&& a[0]!=123456789 {123456789}

a!=null && a.length>0

&& a[0]!=123456789Một số hệ thống sinh kiểm thử tự động cài đặt DSE bằng cách khởi tạo một câythực thi tương trưng để biểu thị các đường đi thực thi khác nhau Nếu như có thể xâydựng được một cây thực thi tượng trưng đầy đủ thì có thể sinh ra các giá trị đầu vàosao cho có thể đạt được sự bao phủ luồng điều khiển (CFG coverage)[5] ở mức cao Với những hệ thống này, mã nguồn chương trình cần được sửa đổi để cho phépthực thi tượng trưng được thực hiện dọc theo việc thực thi cụ thể Chương trình đượcthự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ạitrong 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ươngtrì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ởitạo Trong quá trình thực thi, các giá trị tượng 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ị tượng trưng đó Với mỗi ràngbuộ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ầnthực thi là mỗi lần duyệt một đường đi của SET

Trang 28

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ộctương ứng với nhánh mà đỉnh đó được thêm vào Sau mỗi lần thực thi, một đỉnh màchưa được thăm trong SET sẽ được chọn và ràng buộc đường đi tương ứng với đoạnđường đi từ đỉnh gốc (root) của SET tới đỉnh được chọn đó sẽ được thu gom và ràngbuộc đường đi này sẽ được đưa tới một bộ xử lý ràng buộc (Constraint Solver) để xử

lý Nếu ràng buộc đường đi này không thỏa mãn, một đỉnh khác của SET mà chưađược thăm 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àngbuộ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(terminate) Và các giá trị đầu vào cụ thể được sinh ra cùng với những thông tin phântích được trong mỗi lần thực thi (method summary) 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 đượckết hợp với các thông tin về lỗi phát hiện được nếu lần thực thi đó chương trình ngưnglại vì một ngoại lệ chưa được xử lý, hoặc vì một lỗi nào đó

Ví dụ 2.3: Thực thi tượng trưng với phương thức nhận đầu vào là đối tượng

Ta xét một phương thức nhận 2 tham số đầu vào, một tham số là đối tượngSimpleList và một tham số có kiểu int:

Trang 29

1: void Simple(SimpleList o, int x){

3, với giá trị x= -5 thì điều kiện rẽ nhánh được đánh giá tới false Ràng buộcS(x)=sym+5 <= 0 lưu vào đỉnh tương ứng của SET cho nhánh mà sự thực thi cụ thể đitheo và được đánh dấu là đã được thăm, đồng thời một đỉnh mới đại diện cho nhánhcòn lại được tạo ra và ràng buộc sym+5 > 0 được lưu vào đỉnh này, đỉnh mới được tạo

ra được đánh dấu là chưa được thăm Đến câu lệnh 7 thì một ngoại lệNullPointerException được ném ra và việc thực thi sẽ dừng lại Cây thực thi tượngtrưng được xây dựng tương ứng với lần chạy này (Hình 3(a)) Đỉnh mới được tạo racủa SET mà chưa được thăm được chọn để thu gom ràng buộc trên nhánh tương ứngvới đỉnh chưa được thăm đó Ràng buộc thu gom được là sym+5 > 0 Giải quyết ràngbuộc này ta được một giá trị cụ thể của x giả sử là x=0 Do không có ràng buộc liênquan tới đối tượng l được tạo ra nên giá trị của nó sẽ được khởi tạo với phương thứckhởi tạo mặc định cho lần thực thi tiếp theo

Sau khi khởi tạo đối tượng o và giải quyết ràng buộc, chương trình tiếp tục đượcthực thi với các giá trị đầu vào mới này đó là x=0, o=new simpleList() Đỉnh chưa

1 void Simple(SimpleList o, int x){

Trang 30

được thăm tương ứng với nhánh thực thi này tạo ra từ lần thực thi trước trong SET sẽđược chọn để mở rộng Đến câu lệnh 4, trường value của đối tượng o được truy cậplần đầu tiên Một giá trị tượng trưng sẽ được kết hợp với nó, và giá trị tượng trưng nàyđược cập nhật do giá trị của trường đó được gán với giá trị của biến x Tới câu lệnh 7,một đối tượng o.next sẽ được khởi tạo lười với một giá trị cụ thể và một giá trị tượngtrưng kết hợp với nó, o.next=new simpleList(), R(o.next)=obj2 Tại câu lệnh rẽ nhánhnày, 2 ràng buộc tương ứng với 2 nhánh được tạo ra obj1=obj2, và obj1≠obj2. Ràng buộcobj1≠obj2 tương ứng với nhánh mà sự thực thi cụ thể hiện thời đang đi theo Với ràngbuộc obj1=obj2 thì một đỉnh mới được tạo ra tương ứng với nhánh mà sự thực thi cụ thểhiện thời không đi theo để lưu ràng buộc obj1=obj2 và đỉnh mới này được đánh dấu làchưa được thăm Cây thực thi tượng trưng tương ứng với lần thực thi này được biểu thịtrong Hình 3(b) Sau khi lần chạy này kết thúc đỉnh mới được tạo ra này lại được chọn

để mở rộng và ràng buộc thu gom được trên đường đi chứa đỉnh này là S(x)=sym+5 >

0 && obj1=obj2 && S(o.value)= sym+5 Ràng buộc đối tượng obj1=obj2 được giảiquyết bằng phép gán tham chiếu giữa 2 đối tượng mà các giá trị tượng trưng này đạidiện, o.next=o Đối tượng o lúc này được khởi tạo và giá trị của trường value được gánvới giá trị sinh ra từ việc giải quyết ràng buộc Cây thực thi tương trưng tương ứng vớilần thực thi chương trình với các giá trị đầu vào mới sinh ra này được biểu thị trongHình 3(c)

Hình 3: Cây thực thi tượng trưng được quản lý riêng

Trang 31

2.2 Xây dựng ràng buộc

Các công cụ như Pex[30], CUTE[9] được cài đặt dựa trên kỹ thuật thực thi tượngtrưng động Tuy nhiên, cần có cơ chế để cho phép một chương trình có thể thực thitượng trưng Để thực thi tượng trưng một chương trình thì mã nguồn của chương trình

đó cần được sửa đổi (instrumented) để hỗ trợ việc thực thi tượng trưng Với một sốcông cụ như JCUTE[9] thì các chương trình Java được chuyển đổi thành một dạngngôn ngữ có cấu trúc đơn giản hơn và thêm vào các phần mã hỗ trợ việc thực thi tượngtrưng với ngôn ngữ trung gian này Dạng ngôn ngữ trung gian thường được sử dụngcho ngôn ngữ Java đó là Jimple[17] Bảng 2 dưới minh họa việc mã nguồn Java đượcchuyển thành dạng mã Jimple

Bảng 2 Minh họa việc chuyển đổi từ mã nguồn Java sang mã Jimple

void call(int x){// bắt đầu

Trang 32

phần mã hỗ trợ thực thi tượng trưng thì công cụ Soot[17] được sử dụng để chuyểnchúng về dạng Java bytcode chuẩn.

Việc thực thi tượng trưng một chương trình được biểu thị bằng cây thực thi tượngtrưng Do đó một số hệ thống cài đặt thực thi tượng trưng xây dựng và quản lý câythực thi tượng trưng riêng để mô tả quá trình thực thi tượng trưng một chương trình

Và các ràng buộc trên các đường đi của cây thực thi tượng trưng được quản lý sẽ đượcthu gom và giải quyết bởi bộ xử lý ràng buộc để sinh ra các đầu vào kiểm thử Cộng cụPex cũng xây dựng và quản lý cây thực thi tượng trưng để sinh các đầu vào cho PUT

Ví dụ 2.3 ở trên chính là một minh họa về hệ thống như thế

Hình 4 : Hệ thống kiểm thử tổng quát Kiến trúc tổng quát của hệ thống kiểm thử sử dụng kỹ thuật thực thi tượng trưngđược minh họa như Hình 4 Trong đó Test Input Selector (TIS) làm nhiệm vụ quản lýcây thực thi tượng trưng và sinh các đầu vào để Test Executor thực thi chương trình đãđược sửa đổi để hỗ trợ việc thực thi tượng trưng với mỗi đầu vào được sinh ra đó

2.2.1 Lưu trữ giá trị tượng trưng

Với các hệ thống kiểm thử mà cài đặt kỹ thuật thực thi tượng trưng ở trên thì cần

có các cấu trúc dữ liệu để lưu trữ các giá trị tượng trưng kết hợp với các biến và tham

số đầu vào trong quá trình thực thi tượng trưng một chương trình

Nếu kiểu của biến x không phải là kiểu tham chiếu thì giá trị tượng trưng của xbiểu thị bởi S(x) S’= S[x → s] biểu thị cho ánh xạ từ biến x tới giá trị tượng trưng scủa nó được bổ sung vào S, từ đó S’(x)=s S’=S-x được sử dụng để biểu thị rằng ánh

xạ giữa biến x và giá trị tượng trưng đã được gỡ bỏ S’(x) trong trường hợp này trả vềgiá trị cụ thể cho x mà không phải là giá trị tượng trưng R(o) biểu thị cho giá trị tượngtrưng của đối tượng o R là một ánh xạ giữa đối tượng và giá trị tượng trưng của nótương tự như S Ngoài ánh xạ S và R một ánh xạ M cũng được sử dụng Các ánh xạ S,

R, M được cài đặt bằng cấu trúc dữ liệu dạng Map dùng để lưu trữ các cặp giá trị

key→value Địa chỉ bộ nhớ (memory address) là các định danh duy nhất sử dụng như

Trang 33

key mà các giá trị tượng trưng có thể ánh xạ tới Tuy nhiên, trong Java ta không thểtruy cập tới các con trỏ và địa chỉ bộ nhớ Tên của biến được sử dụng là key trongtrường hợp kiểu của biến đó không phải là kiểu tham chiếu Tuy nhiên tên biến thườngkhông phải là duy nhất do đó các ánh xạ được cài đặt bằng việc thêm một biến tượngtrưng mới cho mỗi biến cục bộ hoặc mỗi trường của đối tượng trong quá trình sửa đổi

mã nguồn của chương trình được kiểm thử Bằng kỹ thuật phân tích dựa trên kiểu[22]

có thể xác định các câu lệnh và các biến liên quan tới các tham số đầu vào để có thểthêm vào phần mã cho chúng để hỗ trợ việc thực thi tượng trưng Các giá trị tượngtrưng được kết hợp với các biến chứ không phải với giá trị của các biến Trong Java

không thể có hai biến có kiểu không phải là kiểu tham chiếu cùng trỏ tới một địa chỉ

bộ nhớ

Với một số đối tượng, có thể có nhiều tham chiếu (reference) tới cùng một đốitượng.Tuy nhiên với đối tượng ta cũng có thể dùng các tham chiếu là key Vì thế ánh

xạ R được cài đặt bằng một cấu trúc dữ liệu dạng Map mà ánh xạ một tham chiếu tới

một giá trị tượng trưng Khi một giá trị tượng trưng của một đối tượng được yêu cầu,một tham chiếu tới đối tượng được tìm kiếm trong R và giá trị tượng trưng ánh xạ tớitham chiếu được trả về nếu tham chiếu được tìm thấy

2.2.2 SE với các kiểu dữ liệu nguyên thủy

Để thực thi tương trưng một chương trình thì mã nguồn của chương trình cầnđược thêm vào các phần mã cho phép việc thực thi tượng trưng Mỗi câu lệnh trongchương trình đó sẽ được xử lý một lần tại một thời điểm và mã thực hiện việc thực thitượng trưng sẽ được thêm vào câu lệnh đó nếu cần thiết Mỗi tham số đầu vào v củachương trình được thay thế bằng một câu lệnh đầu vào tượng trưng getInput(v) Vàchương trình sẽ gọi các câu lệnh đầu vào tượng trưng này như là các tham số đầu vào.Mỗi lần trước khi bắt đầu thực thi một lệnh, phần thực thi tượng trưng củachương trình sẽ được khởi tạo Trong quá trình khởi tạo, một kết nối được thiết lập với

bộ lựa chọn dữ liệu kiểm thử (TIS) TIS sinh ra một dãy các giá trị cụ thể để làm đầuvào cho chương trình Các giá trị đầu vào nhận được từ TIS được lưu vào một bộ nhớ

I I là một ánh xạ cài đặt bởi cấu trúc dữ liệu Map, ánh xạ mỗi tham số đầu vào tới mộtgiá trị đầu vào cụ thể Nói cách khác bộ nhớ I có thể xem như một dãy các giá trị đầuvào được sắp xếp theo thứ tự Ví dụ khi câu lệnh đầu vào tượng trưng đầu tiên đượcthực thi thì giá trị đầu tiên của dãy được sử dụng Nếu một số tham số đầu vào củachương trình không được thay thế với câu lệnh đầu vào tượng trưng thì chương trình

sẽ không được thực thi theo đường đi mong đợi

Trang 34

Mỗi câu lệnh getInput(v) là một phương thức được cài đặt để thực hiện việc gánmột giá trị đầu vào cụ thể và giá trị tượng trưng cho tham số đầu vào Lúc bắt đầu thựcthi giá trị tượng trưng của tham số đầu vào được gán bằng một ký hiệu đầu vào duynhất và nó được đưa tới TIS để giá trị tượng trưng này đại diện cho giá trị đầu vào cụthể mới Với các giá trị đầu vào cụ thể, ta cần kiểm tra xem có còn các giá trị cụ thểtrong I chưa được chọn để thực thi Nếu không một giá trị được sinh ngẫu nhiên sẽđược sử dụng.

getInput(v) 1: S[v→ s i ]; // s i is a new symbolic value 2: i = i + 1;

Ngày đăng: 25/04/2013, 19:30

Nguồn tham khảo

Tài liệu tham khảo Loại Chi tiết
[1] B. Beizer. Software Testing Techniques. Van Nostrand Reinhold Co., New York,NY, USA, 2nd edition, 1990 Sách, tạp chí
Tiêu đề: Software Testing Techniques
[2] Daniel Kroening ã Ofer Strichman. Decision Procedures: An Algorithmic Point of View, © 2008 Springer-Verlag Berlin Heidelberg Sách, tạp chí
Tiêu đề: An Algorithmic Point of View
[3] E. Gamma, R. Helm, R. Johnson, and J. M. Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley, 1994 Sách, tạp chí
Tiêu đề: Design Patterns: Elements of Reusable Object-Oriented Software
[4] Edmund M. Clarke, Orna Grumberg, and Doron A. Peled. Model Checking. The MIT Press, January 2000 Sách, tạp chí
Tiêu đề: Model Checking
[5] H. Zhu, P. Hall, J. May. Software Unit Test Coverage and Adequacy. ACM Computing Surveys, 29 (4). ISSN 0360-0300, December 1997, pp. 366–427 Sách, tạp chí
Tiêu đề: Software Unit Test Coverage and Adequacy. ACMComputing Surveys, 29 (4). ISSN 0360-0300
[6] J. C. King. Symbolic execution and program testing. Commun. ACM, 19(7):385–394, 1976 Sách, tạp chí
Tiêu đề: Symbolic execution and program testing
[7] J. de Halleux and N. Tillmann. Parameterized unit testing with Pex (tutorial). In Proc. of Tests and Proofs (TAP’08), volume 4966 of LNCS, pages 171–181, Prato,Italy, April 2008. Springer Sách, tạp chí
Tiêu đề: Parameterized unit testing with Pex (tutorial)
[8] Jon Edvardsson. Techniques for Automatic Generation of Tests from Programs and Specifications. Department of Computer and Information Science Linkoping SE-581, Sweden 2006 Sách, tạp chí
Tiêu đề: Techniques for Automatic Generation of Tests from Programs andSpecifications
[9]Koushik Sen. Scalable automated methods for dynamic program analysis. Electro-nic version of doctoral thesis, Department of Computer Science, University of Illinois at Urubana Champaign, 2006 Sách, tạp chí
Tiêu đề: Scalable automated methods for dynamic program analysis
[12] N. Tillmann and W. Schulte. Parameterized unit tests. In Proceedings of the 10thEuropean Software Engineering Conference held jointly with 13th ACM SIG-SOFT International Symposium on Foundations of Software Engineering, pages 253–262.ACM, 2005 Sách, tạp chí
Tiêu đề: Parameterized unit tests
[13] Patrice Godefroid. Compositional dynamic test generation. In Proceedings ofthe 34th ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages (POPL), pages 47-54. ACM, 2007 Sách, tạp chí
Tiêu đề: Compositional dynamic test generation". In Proceedings ofthe34th ACM SIGPLAN-SIGACT Symposium on Principles of Programming "Languages(POPL)
[14] Patrice Godefroid, Nils Klarlund, and Koushik Sen. Dart: directed automated random testing. In Proceedings of the ACM SIGPLAN 2005 Conference on program- ming Language Design and Implementation (PLDI), pages 213-223. ACM, 2005 Sách, tạp chí
Tiêu đề: Dart: directed automatedrandom testing
[15] Peli de Halleux and Nikolai Tillmann, Parameterized Test Patterns For Effective Testing with Pex. Copyright Microsoft Corporation.October 21, 2008 Sách, tạp chí
Tiêu đề: Parameterized Test Patterns For EffectiveTesting with Pex
[16] Petri Ihantola. Automatic test data generation for programming exercises withsymbolic execution and Java PathFinder. Master's thesis, Helsinki University of Technology, Departement of Theoretical Computer Science, 2006 Sách, tạp chí
Tiêu đề: Automatic test data generation for programming exerciseswithsymbolic execution and Java PathFinder". Master's thesis, Helsinki University of"Technology, Departement of Theoretical Computer Science
[17] Raja Vallée-Rai, Phong Co, Etienne Gagnon, Laurie J. Hendren, Patrick Lam, and Vijay Sundaresan. Soot - a Java bytecode optimization framework. In Proceedings of the 1999 conference of the Centre for Advanced Studies on Collaborative Research (CASCON), page 13. IBM, 1999 Sách, tạp chí
Tiêu đề: Soot - a Java bytecode optimization framework
[18]R. Ferguson and B. Korel. The chaining approach for software test data generation.IEEE Transactions on Software Engineering, 5(1):63–86, January 1996 Sách, tạp chí
Tiêu đề: The chaining approach for software test data generation
[19]S. Anand, P. Godefroid, and N. Tillmann. Demand-driven compositional symbolic execution. In Proc. of TACAS’08, volume 4963 of LNCS, pages 367–381. Springer, 2008 Sách, tạp chí
Tiêu đề: Demand-driven compositional symbolicexecution
[20] Sarfraz Khurshid, Corina S. Pasareanu, and Willem Visser. Generalized symbolic execution for model checking and testing. In 9th International Conference on Tools and Algorithms for the Construction and Analysis of Systems (TACAS), volume 2619 of Lecture Notes in Computer Science, pages 553-568. Springer, 2003 Sách, tạp chí
Tiêu đề: Generalized symbolicexecution for model checking and testing
[21] Saswat Anand, Corina S. Pasareanu, and Willem Visser. Symbolic execution with abstraction. International Journal on Software Tools for Technology Transfer (STTT) Volume 11 , Issue 1 Pages 53-67 , January 2009 Sách, tạp chí
Tiêu đề: Symbolic execution withabstraction
[22] Saswat Anand, Alessandro Orso, and Mary Jean Harrold. Type-dependence analysis and program transformation for symbolic execution. In 13th International Conference on Tools and Algorithms for the Construction and Analysis of Systems (TACAS), volume 4424 of Lecture Notes in Computer Science, pages 117-133. Springer, 2007 Sách, tạp chí
Tiêu đề: Type-dependenceanalysis and program transformation for symbolic execution". In 13th InternationalConference on Tools and Algorithms for the Construction and Analysis of "Systems(TACAS), volume 4424 of Lecture Notes in Computer Science

HÌNH ẢNH LIÊN QUAN

Hình 1: Mối quan hệ giữa UT và PUT - SINH CA KIỂM THỬ THAM SỐ HÓA CHO CHƯƠNG TRÌNH JAVA
Hình 1 Mối quan hệ giữa UT và PUT (Trang 15)
Hình 2 : Cây thực thi tượng trưng - SINH CA KIỂM THỬ THAM SỐ HÓA CHO CHƯƠNG TRÌNH JAVA
Hình 2 Cây thực thi tượng trưng (Trang 23)
Bảng 1: Ví dụ về thực thi tượng trưng động - SINH CA KIỂM THỬ THAM SỐ HÓA CHO CHƯƠNG TRÌNH JAVA
Bảng 1 Ví dụ về thực thi tượng trưng động (Trang 26)
Hình 3: Cây thực thi tượng trưng được quản lý riêng - SINH CA KIỂM THỬ THAM SỐ HÓA CHO CHƯƠNG TRÌNH JAVA
Hình 3 Cây thực thi tượng trưng được quản lý riêng (Trang 29)
Bảng 2. Minh họa việc chuyển đổi từ mã nguồn Java sang mã Jimple - SINH CA KIỂM THỬ THAM SỐ HÓA CHO CHƯƠNG TRÌNH JAVA
Bảng 2. Minh họa việc chuyển đổi từ mã nguồn Java sang mã Jimple (Trang 30)
Hình 4 : Hệ thống kiểm thử tổng quát - SINH CA KIỂM THỬ THAM SỐ HÓA CHO CHƯƠNG TRÌNH JAVA
Hình 4 Hệ thống kiểm thử tổng quát (Trang 31)
Hình 5: Gán giá trị tượng trưng cho tham số đầu vào - SINH CA KIỂM THỬ THAM SỐ HÓA CHO CHƯƠNG TRÌNH JAVA
Hình 5 Gán giá trị tượng trưng cho tham số đầu vào (Trang 33)
Hình 6: Thực thi tượng trưng với câu lệnh gán - SINH CA KIỂM THỬ THAM SỐ HÓA CHO CHƯƠNG TRÌNH JAVA
Hình 6 Thực thi tượng trưng với câu lệnh gán (Trang 34)
Hình 7: Thực thi tượng trưng với câu lệnh rẽ nhánh - SINH CA KIỂM THỬ THAM SỐ HÓA CHO CHƯƠNG TRÌNH JAVA
Hình 7 Thực thi tượng trưng với câu lệnh rẽ nhánh (Trang 34)
Bảng 3: Sửa đổi chương trình với câu lệnh liên quan tới đối tượng - SINH CA KIỂM THỬ THAM SỐ HÓA CHO CHƯƠNG TRÌNH JAVA
Bảng 3 Sửa đổi chương trình với câu lệnh liên quan tới đối tượng (Trang 35)
Hình 8: Khởi tạo đối tượng làm đầu vào cho chương trình - SINH CA KIỂM THỬ THAM SỐ HÓA CHO CHƯƠNG TRÌNH JAVA
Hình 8 Khởi tạo đối tượng làm đầu vào cho chương trình (Trang 36)
Hình 10: Thuật toán sinh dữ liễu kiểm thử - SINH CA KIỂM THỬ THAM SỐ HÓA CHO CHƯƠNG TRÌNH JAVA
Hình 10 Thuật toán sinh dữ liễu kiểm thử (Trang 39)
Hình 11: Các cây thực thi cục bộ tương ứng với hàm abs và TestAbs - SINH CA KIỂM THỬ THAM SỐ HÓA CHO CHƯƠNG TRÌNH JAVA
Hình 11 Các cây thực thi cục bộ tương ứng với hàm abs và TestAbs (Trang 41)
Hình 12: Kiến trúc JPF - SINH CA KIỂM THỬ THAM SỐ HÓA CHO CHƯƠNG TRÌNH JAVA
Hình 12 Kiến trúc JPF (Trang 44)
Hình 13: Bộ sinh lựa chọn trong JPF - SINH CA KIỂM THỬ THAM SỐ HÓA CHO CHƯƠNG TRÌNH JAVA
Hình 13 Bộ sinh lựa chọn trong JPF (Trang 46)

TỪ KHÓA LIÊN QUAN

TRÍCH ĐOẠN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w