Các toán tử đột biến mức lớp

Một phần của tài liệu Kỹ thuật kiểm thử đột biến và ứng dụng để kiểm thử các chương trình Java (Trang 54)

Bảng 4.2 sẽ mô tả ngắn gọn các toán tử mức lớp thực thi trong MuJava. Các toán tử này được chia thành bốn loại tùy theo cách sử dụng của chúng trong ngôn ngữ lập trình hướng đối tượng (OOP). Ba nhóm đầu tiên dựa trên các tính năng chung cho tất cả các OOP. Nhóm cuối cùng bao gồm các tính năng đặc trưng của Java. Các nhóm đó là:

1. Đóng gói (Encapsulation) 2. Tính kế thừa (Inheritance) 3. Tính đa xạ (Polymorphism)

4. Các tính năng đặc trưng của Java (Java-Specific Features)

Tương tự như các toán tử đột biến mức phương thức, các toán tử đột biến mức lớp thay đổi cú pháp chương trình bằng cách thêm, xóa hay sửa đổi các biểu thức cần kiểm thử. Trong MuJava có tất cả 29 toán tử mức lớp.

Tính năng

ngôn ngữ Toán tử Mô tả

Đóng gói AMC Thay đổi bổ nghĩa truy cập

Tính kế thừa

IHD Xóa biến ẩn IHI Thêm biến ẩn

IOD Xóa phương thức viết đè

IOP Thay đổi vị trí gọi phương thức viết đè IOR Đổi tên phương thức viết đè

ISI Thêm từ khóa super ISD Xóa từ khóa super

IPC Xóa lời gọi constructor của lớp cha

Tính đa hình

PNC Gọi phương thức new bằng kiểu của lớp con PMD Khai báo biến thành viên bằng kiểu của lớp cha

PPD Khai báo biến thành viên bằng kiểu của lớp con PCI Thêm toán tử chuyển đổi kiểu (type cast )

PCC Thay đổi kiểu chuyển đổi PCD Xóa toán tử chuyển đổi kiểu

PRV Chỉ định tham chiếu bằng kiểu tương thích khác OMR Thay đổi nội dung phương thức nạp chồng OMD Xóa phương thức nạp chồng

OAN Thay đổi gọi các đối số của phương thức nạp chồng

Các tính năng đặc trưng

của Java

JTI Thêm từ khóa this JTD Xóa từ khóa this

JSI Thêm bổ từ static JSD Xóa bổ từ static

JID Xóa khởi tạo biến thành viên

EOA Thay thế chỉ định nội dung và chỉ định tham chiếu EOC Thay thế so sánh nội dung và so sánh tham chiếu EAM Thay đổi phương thức truy cập

EMM Thay đổi phương thức bổ nghĩa

Bảng 4.2- Các toán tử đột biến mức lớp trong MuJava

4.1.3. Phƣơng pháp thực thi của MuJava

MuJava thực thi phương pháp “làm nhanh hơn” để kiểm thử đột biến nhằm tiết kiệm thời gian biên dịch [6]. Cách tiếp cận này đã được áp dụng chủ yếu cho các chương trình hướng đối tượng.

Kiến trúc của MuJava sử dụng phương pháp tiếp cận tạo lược đồ đột biến (MSG). Cách tiếp cận này hoạt động bằng cách tạo ra một siêu đột biến (metamutant) của tất cả các chương trình đột biến và yêu cầu chỉ có hai biên dịch: biên dịch chương trình gốc và biên dịch chương trình metamutant. MuJava sử dụng hai loại toán tử đột biến:

 Các toán tử làm thay đổi cấu trúc của chương trình  Các toán tử làm thay đổi hành vi của chương trình

Các thành phần khác nhau tạo ra các đột biến cấu trúc và hành vi. Đối với những đột biến hành vi, phản ánh thời gian biên dịch được sử dụng để phân tích chương trình gốc. Sau đó, máy MSG sử dụng phản ánh thời gian biên dịch cũng như để tạo ra chương trình siêu đột biến. Đối với các đột biến cấu trúc, mã nguồn gốc được biên dịch bằng cách sử dụng các trình biên dịch Java. Sau đó, BCEL API được sử dụng để thêm hoặc xoá các thành viên lớp trong kết quả bản dịch byte code.

4.2. Công cụ Junit

Các ngôn ngữ lập trình như ASP, C++, C, C#, Delphi,… đều có bộ hỗ trợ kiểm thử đơn vị riêng của nó. JUnit, được xây dựng bởi Erich Gamma và Kent Beck, là một framework được dùng cho kiểm thử đơn vị trong Java cho phép các nhà phát triển dễ dàng tạo ra các ca kiểm thử cho các chương trình Java. Bên cạnh đó, JUnit còn cung cấp một phương tiện xác nhận việc kiểm tra các kết quả mong đợi so với các kết quả thực tế.

Hình 4.6 – Giao diện đồ họa của JUnit

Khi JUnit thực thi các phép thử, nếu tất cả các phép thử đều thành công (tức là kết quả mong đợi và kết quả thực tế trùng khớp với nhau) thì trên giao diện đồ họa của JUnit sẽ hiển thị thanh màu xanh, còn nếu có một hoặc nhiều

hơn một phép thử thất bại hoặc bị lỗi (tức là kết quả mong đợi không giống kết quả thực tế) thì JUnit sẽ hiển thị thanh màu đỏ, được minh họa ở hình 4.2. Chi tiết việc hướng dẫn sử dụng và cài đặt JUnit có thể được tìm thấy từ địa chỉ

http://www.junit.org.

4.3. Quy trình ứng dụng kiểm thử đột biến để kiểm thử các chƣơng trình Java chƣơng trình Java

Quy trình ứng dụng kiểm thử đột biến để kiểm thử các chương trình Java, được thực hiện theo sơ đồ sau:

Hình 4.7 - Quy trình ứng dụng kỹ thuật kiểm thử đột biến

Quy trình trên được thực hiện theo ba bước:

Bƣớc 1: Dùng JUnit kiểm thử chương trình P, nếu P bị lỗi thì tiến hành sữa

chữa P, nếu P không còn lỗi nữa chuyển sang bước 2.

Bƣớc 2: MuJava phân tích chương trình P để tạo các đột biến P’. Trong

quá trình tạo đột biến, MuJava gọi lệnh biên dịch đột biến đó (tự động) nếu có lỗi thì bỏ qua, tạo và biên dịch đột biến tiếp theo.

Chương trình P JUnit Chỉnh sửa P Tốt ? Không tốt Đột biến P’ MuJava Tốt KẾT QUẢ Thực thi đột biến P’ MuJava

Bƣớc 3: Tiếp tục dùng MuJava để phân tích và thực thi các đột biến P’ với

các dữ liệu thử được thiết kế sẵn theo định dạng mà MuJava yêu cầu. Kết quả sau khi thực thi gồm: tổng số đột biến bị diệt, tổng số đột biến còn sống, và tỷ lệ đột biến.

4.4. Ứng dụng kỹ thuật kiểm thử đột biến để kiểm thử chƣơng trình SXQSort.java chƣơng trình SXQSort.java

Khi dùng công cụ MuJava để tạo đột biến, số lượng chương trình đột biến được tạo ra là rất lớn, tốn rất nhiều thời gian để thực thi các đột biến với các dữ liệu thử (như đã phân tích ở chương 3). Do đó, chương trình sắp xếp dãy số tăng dần theo thuật toán QuickSort (SXQSort.java) được lựa chọn để kiểm thử đột biến, là chương trình đơn giản có thời gian thực thi nhanh với thời gian thực hiện trung bình O(nlog2n), trong trường hợp xấu nhất O(n2) khi dãy A đã được sắp xếp.

4.4.1. Đặc tả của chƣơng trình sắp xếp dãy số tăng dần

Với P là chương trình sắp xếp dãy số tăng dần, S là bảng đặc tả cho P như sau:

 P nhận đầu vào một số nguyên N (1  N  30) và một dãy gồm N số nguyên gọi là các phần tử của dãy. 0  K  e - 1 với e nào đó.

 K là phần tử bất kỳ của dãy.

 Chương trình P sắp xếp dãy theo thứ tự tăng dần và xuất ra dãy đã sắp xếp.

P được xem là đúng với đặc tả S nếu và chỉ nếu: với mỗi đầu vào hợp lệ, đầu ra tương ứng với đặc tả S.

4.2.2. Thuật toán của chƣơng trình SXQSort.java

Chúng ta xét dãy A gồm N phần tử A[1] .. A[N]. Giả sử v là một giá trị khóa mà ta gọi là chốt (Pivot). Ta phân hoạch dãy A[1] .. A[N] thành hai dãy con "bên trái" và "bên phải". Dãy con "bên trái" bao gồm các phần tử có khóa nhỏ hơn chốt, dãy con "bên phải" bao gồm các phần tử có khóa lớn hơn hoặc bằng chốt. Sắp xếp dãy con “bên trái” và dãy con “bên phải” thì dãy đã cho sẽ được sắp bởi vì tất cả các khóa trong dãy con “bên trái” đều nhỏ hơn các khóa trong dãy con “bên phải”. Việc sắp xếp các dãy con “bên trái” và “bên phải” cũng được tiến hành bằng phương pháp nói trên.

Với ý tưởng trên, chương trình sắp xếp dãy số tăng dần theo thuật toán QuickSort được chia làm ba module có cấu trúc như sau:

FindPivot: Chọn khóa lớn nhất trong hai phần tử có khóa khác nhau đầu tiên kể từ trái qua. Nếu dãy chỉ gồm một phần tử hay gồm nhiều phần tử có khóa bằng nhau thì không có chốt.

Partiton: Ðể phân hoạch dãy ta dùng 2 "con nháy" L và R. Trong đó L từ bên trái và R từ bên phải, ta cho L chạy sang phải cho tới khi gặp phần tử có khóa >= chốt và cho R chạy sang trái cho tới khi gặp phần tử có khóa < chốt. Tại chỗ dừng của L và R nếu L < R thì hoán vị a[L], a[R]. Lặp lại quá trình dịch sang phải, sang trái của 2 "con nháy" L và R cho đến khi L > R. Khi đó L sẽ là điểm phân hoạch, cụ thể là a[L] là phần tử đầu tiên của dãy con “bên phải”.

QuickSort: Sử dụng biến PivotIndex để lưu giữ kết quả trả về của hàm FindPivot, nếu biến PivotIndex nhận được một giá trị khác -1 thì mới tiến hành phân hoạch dãy. Ngược lại, dãy không có chốt và do đó đã có thứ tự. Biến Pivot sẽ được sử dụng để lưu giữ giá trị chốt và biến k để lưu giữ giá trị của điểm phân hoạch do hàm Partition trả về. Sau khi dãy A đã phân hoạch xong ta sẽ gọi đệ quy QuickSort cho dãy con “bên trái” A[i] .. A[k-1] và dãy con “bên phải” A[k] .. A[j].

Như vậy, để sắp xếp dãy A gồm N phần tử, ta chỉ cần gọi QuickSort(0,n-1).

4.2.3. Thiết kế các trƣờng hợp kiểm thử cho chƣơng trình SXQSort.java

Các trường hợp kiểm thử sẽ được thiết kế cho từng module của chương trình SXQSort.java, dựa trên kỹ thuật kiểm thử hộp trắng, kỹ thuật kiểm thử hộp đen, và kết hợp với sự suy đoán để tìm ra các trường hợp kiểm thử có khả năng phát hiện các lỗi có thể của chương trình.

4.2.3.1. Thiết kế các trường hợp kiểm thử cho module FindPivot

Module FindPivot có chức năng là tìm chốt cho dãy A gồm N phần tử A[1] .. A[N]. Có hai khả năng xảy ra đối với dãy A:

 Dãy A không có chốt nếu dãy chỉ có một phần tử hoặc nhiều phần tử có khóa bằng nhau.

QuickSort

Partition

 Dãy A có chốt thì chốt sẽ là khóa lớn nhất trong hai phần tử có khóa khác nhau đầu tiên kể từ trái qua.

Dựa trên điều kiện này, các trường hợp kiểm thử cho module FindPivot được thiết kế như sau:

STT Tên kiểm thử Đầu vào

Kết quả mong đợi

N Dãy A 1 FindPivot1 6 6 6 5 8 7 4 6 6 5 8 7 Chốt là 6 (khóa của phần tử đầu tiên) 2 FindPivot2 6 6 6 7 5 7 4 6 6 7 5 7 4 Chốt là 7 (khóa của phần tử thứ 3) 3 FindPivot3 5 9 4 1 6 7 9 4 1 6 7 Chốt là 9 (khóa của phần tử đầu tiên) 4 FindPivot4 5 2 8 2 5 5 2 8 2 5 5 Chốt là 8 (khóa của phần tử thứ 2) 5 FindPivot5 5 2 2 2 2 2 Không có chốt (vì các phần tử có khóa bằng nhau) 6 FindPivot6 1 9 Không có chốt (vì có một phần tử)

4.2.3.2. Thiết kế các trường hợp kiểm thử cho Module Partition

Đoạn chương trình phân hoạch dãy A thành hai dãy con A[i] .. A[L-1] và A[L] .. A[j] với điểm phân hoạch là L như sau:

public int Partition(int i,int j,int Pivot) { int L,R;

L = i; //1

R = j; //1

while (L <= R) { //2

while (A[L] < Pivot) //4

L++; //5

while (A[R] >= Pivot) //6

R--; //7 if (L < R) { //8 int tmp; tmp = A[L]; //9 A[L] = A[R]; //9 A[R] = tmp; //9 } } //10 return L; //3 }

Áp dụng phương pháp đường dẫn cơ sở để thiết kế các trường hợp kiểm thử cho module Partition, được thực hiện theo các bước sau:

 Xây dựng đồ thị luồng điều khiển cho đoạn chương trình Partition (với

các đỉnh của đồ thị tương ứng với các dòng lệnh được đánh số ở phần chú thích của đoạn chương trình trên )

Hình 4.8 - Đồ thị luồng điều khiển của Partiton

(Đồ thị có 4 đỉnh điều kiện: 2, 4, 6, 8 )

 Đối chiếu với hình 4.8, xác định độ phức tạp chu trình V(G) như sau: V(G) = P (số đỉnh điều kiện) + 1 = 4 + 1 = 5

 Xác định tập cơ sở của các đường dẫn độc lập. Vì V(G) =5 nên đồ thị luồng điều khiển ở hình 4.8 có 5 đường dẫn độc lập như sau:

+ Đường dẫn 1: 1  2  3

+ Đường dẫn 2: 1  2  4  6  8  10  2  …

+ Đường dẫn 3: 1  2  4  6  8  9  10  2  …

+ Đường dẫn 4: 1  2  4  5  4  …

+ Đường dẫn 5: 1  2  4  6  7  6  …

Các dấu chấm lửng (…) phía sau các đường dẫn có nghĩa là một đường dẫn bất kỳ đi qua phần còn lại của đồ thị đều có thể chấp nhận được.

 Thiết kế các trường hợp kiểm thử cho các đường dẫn 3, 4, 5 như sau:

1 2 4 5 6 7 8 9 10 3 F T T T T F F F

STT Tên kiểm thử

Đầu vào

Kết quả mong đợi

N Dãy A

1 PartitionPath3 5 15 2 9 7 3 3 2 9 7 15

Điểm phân hoạch: 4 2 PartitionPath4 6 2 2 6 1 8 7 2 2 1 6 8 7

Điểm phân hoạch: 3 3 PartitionPath5 6 6 2 8 4 7 10 4 2 8 6 7 10

Điểm phân hoạch: 2

Bảng 4.4 – Mô tả các trường hợp kiểm thử cho module Partition

(Lưu ý: Đường dẫn 1 và 2 không thể kiểm thử một mình, mà phải được kiểm thử như là một phần của các kiểm thử đường dẫn 3, 4, 5.)

4.2.3.3. Thiết kế các trường hợp kiểm thử cho Module QuickSort

Đây là module cuối cùng gọi thực hiện FindPivot, Partiton và gọi đệ quy QuickSort. Do đó, khả năng xảy ra lỗi ở module này có thể xảy ra. Vì vậy, chúng ta cần thiết kế các trường hợp kiểm thử cho module này để thực hiện việc kiểm thử tích hợp khi các module con được tích hợp lại thành module QuickSort.

Dựa vào phương pháp kiểm thử hộp đen bằng cách sử dụng phân hoạch tương đương và phân tích giá trị biên đối với các giá trị đầu vào:

 Số phần tử của dãy N (1  N  30): 0, 1, 5, 8, 30, 31, chữ cái, 2.5  Dãy A:

+ Các phần tử của dãy là ngẫu nhiên

+ Các phần tử của dãy đều có giá trị bằng nhau

+ Dãy đã theo thứ tự tăng dần

+ Dãy theo thứ tự giảm dần

+ Dãy có một phần tử là chữ cái

+ Dãy có một phần tử là số thực

Từ việc phân tích các giá trị đầu vào của thuật toán sắp xếp QuickSort, chúng ta thiết kế được các trường hợp kiểm thử như sau:

STT Tên kiểm thử

Đầu vào

Kết quả mong đợi

N Dãy A 1 QuickSort1 0 [] Thất bại 2 QuickSort2 1 5 5 3 QuickSort3 5 4 5 7 2 2 2 2 4 5 7 4 QuickSort4 4 4 4 4 4 4 4 4 4 4 5 QuickSort5 1 5 10 17 30 1 5 10 17 30 6 QuickSort6 16 12 3 1 0 0 1 3 12 16 7 QuickSort7 8 8 15 6 2 5 4 12 7 2 4 5 6 7 8 12 15 8 QuickSort8 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 9 QuickSort9 2 3 6 8 12 16 19 25 2 3 6 8 12 16 19 25 10 QuickSort10 17 10 8 5 4 2 1 -3 -3 1 2 4 5 8 10 17 11 QuickSort11 30 8 15 6 2 5 … 10 2 5 6 8 10 15… 12 QuickSort12 6 6 6 6 6 6… 6 6 6 6 6 6… 13 QuickSort13 2 6 8 12 …15 2 6 8 12 15… 14 QuickSort14 17 10 8 5 ….-3 -3 5 8 10 17… 15 QuickSort15 31 5 -4 3 20 1…… Thất bại 16 QuickSort16 a Thất bại 17 QuickSort17 3 5 6 a Thất bại 18 QuickSort18 2.5 Thất bại 19 QuickSort19 5 3 6 7 2 1.5 Thất bại

Bảng 4.5 – Mô tả các trường hợp kiểm thử cho module QuickSort

Như vậy, có tất cả 28 trường kiểm thử được thiết kế để kiểm thử cho chức năng của từng module và cho toàn bộ hệ thống của chương trình SXQSort.java.

Trong đó, có 22 trường hợp kiểm thử được mong đợi làm cho chương trình thành công và 6 trường hợp kiểm thử được mong đợi làm cho chương trình thất bại. Chúng ta chọn 22 trường hợp kiểm thử được mong đợi làm cho chương trình SXQSort.java thành công để thực hiện kiểm thử đột biến.

4.4.4. Kiểm thử chƣơng trình SXQSort.java với JUnit

Chương trình SXQSort.java phải được hiển thị để cung cấp các đầu ra mong muốn khi thực hiện với 22 trường hợp kiểm thử (được mong đợi làm cho chương trình thành công). Vì trong quá trình thực hiện kiểm thử đột biến, bên cạnh các đột biến tương đương, tất cả các đột biến khác được hiển thị để tạo các đầu ra không đúng so với đầu ra đúng của chương trình SXQSort.java. Nếu có bất kỳ đầu ra nào là không đúng thì chứng tỏ rằng chương trình SXQSort.java chứa lỗi. Các lỗi này nên được sữa chữa để bắt đầu quá trình kiểm thử đột biến.

Một phần của tài liệu Kỹ thuật kiểm thử đột biến và ứng dụng để kiểm thử các chương trình Java (Trang 54)

Tải bản đầy đủ (PDF)

(76 trang)