Khái niệm kiểm thử đột biế n

Một phần của tài liệu Bài giảng kiểm thử phần mềm đh phạm văn đồng (Trang 95 - 104)

Kiểm thử đột biến được thiết kế nhằm tạo ra dữ liệu thử hiệu quả, nghĩa là có khả năng phát hiện lỗi của chương trình. Trong khi thực hiện kiểm thử đột biến, chúng ta tạo ra các phiên bản lỗi của chương trình gốc bằng cách chèn lỗi vào mã nguồn của nó. Sau đó, thực thi kiểm thử với lần lượt các dữ liệu thử cho từng phiên bản lỗi. So sánh kết quả đầu ra của từng phiên bản lỗi với chương trình gốc, từ đó đánh giá được khảnăng phát hiện lỗi của các dữ liệu thử.

Các phiên bản lỗi được tạo ra từ chương trình gốc được gọi là các đột biến (mutant). Một cách cụ thể, đột biến P’ của chương trình gốc P là một chương trình tương tự với chương trình gốc P; P’ khác P do chỉ một thay đổi cú pháp trong chương trình. Chẳng hạn, trong Bảng 3.26, P là chương trình gốc, P’ và P’’ là các đột biến của P bằng cách thay đổi cú pháp trong phép toán quan hệ, thay thế (x>10) bởi (x<10) đối với P’; thay (x=0) bởi (x! = 0) đối với P’’. Các câu lệnh bị đột biến được đánh dấu bởi kí hiệu ∆.

Bảng 3.26. Ví dụ minh họa các đột biến

Chương trình gốc P Đột biến P’ Đột biến P’’

1. int x; 2. if ( x = 0) 3. doThis (); 4. if ( x > 10) 5. doThat(); 1. int x; 2. if ( x = 0) 3. doThis (); 4. ∆if ( x < 10) 5. doThat(); 1. Int x; 2. ∆if ( x ! = 0) 3 doThis (); 4 If ( x>10)

5 doThat ();

Kiểm thử đột biến được xây dựng dựa trên hai giả thuyết cơ bản: “Giả thuyết lập trình viên giỏi” (competent programmer hypothesis) và “giả thuyết hiệu ứng liên kết”

(coupling effeet hypothesis). Giả thuyết lập trình viên giỏi cho rằng thông thường các lập trình viên đều rất giỏi và họ sẽ không bao giờ viết ra các chương trình một cách tùy tiện, cẩu thả. Như vậy, một lập trình viên trong quá trình viết lệnh cho chương trình nếu có sai sót, thì cũng sẽ tạo ra được chương trình rất gần với chương trình được cho là đúng, có nghĩa là chương trình không đúng đó chỉ vó một vài thay đổi về cú pháp rất nhỏ so với chương trình đúng. Những thay đổi nhỏ này nếu không được phát hiện và chỉnh sửa, nó sẽ làm cho kết quả đầu ra không như mong muốn. Các chương trình này vẫn được biên dịch và thực thi một cách bình thường và lập trình viên không thể phát hiện ra được lỗi của nó. Hơn thế, các chương trình này có thể được đánh giá tốt trong các quá trình kiểm thử. Các lỗi phạm phải bởi lập trình viên được gọi là các lỗi đơn giản. Do vậy, trong kiểm thử đột biến, chỉ các lỗi đơn giản được tạo ra bởi việc thực hiện các thay đổi nhỏ về cú pháp được áp dụng, nhằm biểu diễn các lỗi phạm phải bởi các “lập trình viên giỏi”.

Giả thuyết hiệu ứng liên kết cho rằng các lỗi phức tạp được liên kết từ các lỗi đơn giản, như vậy bộ dữ liệu thử đủ khả năng phát hiện tất cả các lỗi đơn giản trong chương trình thì cũng có khả năng phát hiện các lôi phức tạp với tỉ lệ cao. Có nhiều nghiên cứu lí thuyết cũng như nghiên cứu thực nghiệm đã khẳng định rằng giải thuyết hiệu ứng liên kết đột biến là thực thể và đúng.

3.7.2. Một số khái niệm cơ bản

Toán tửđột biến

Toán tử đột biến (mutation operator) là một luật được áp dụng vào chương trình gốc để tạo ra các phiên bản đột biến. Nó có thể làm việc thay thế một toán tử này bằng một toán tử khác; thay đổi toán hạng của biểu thức; xóa toàn bộ các biểu thức; thay đổi câu lệnh… hay có thể được tạo ra bằng cách thay đổi nhỏ về cú pháp của chương trình theo hướng mà các lập trình viên thường phạm phải. Các toán tử đột biến được xây dựng dựa trên ngôn ngữ dùng để cài đặt lại chương trình được kiểm thử.

Xét một ví dụ về đột biến các toán tử số học, giả sử chúng có tập 4 các toán tử số học như sau: { +, -, *, / }. Toán tử đột biến thay thế mỗi toán tử số học trong chương trình bởi các toán tử số học khác. Giả sử đoạn mã nguồn gốc cần kiểm thử là một câu lệnh:

a = b * ( c – d);

Chúng ta có thể tạo ra sáu đột biến ( từΔ1 đến Δ6 ) bởi thay thế các toán tử nhân và trừnhư sau: Δ1 a = b + (c – d); Δ2 a = b - (c – d); Δ3 a = b / (c – d); Δ4 a = b * (c + d); Δ5 a = b * (c *d); Δ6 a = b * (c / d);

Như vậy, áp dụng một toán tử đột biến có thể sinh ra nhiều phiên bản đột biến cho một chương trình gốc.

Các toán tử đột biến điển hình thường được thiết kế để thay đổi các biến và các biểu thức bởi việc thay thế, chèn thêm hay xóa các toán tử và toán hạng. Bảng 3.27 liệt kê tập các toán tử đột biến này là cơ sở cho các tập toán tử đột biến khác được nghiên cứu và phát triển về sau cho các ngôn ngữ lập trình khác.

Bảng 3.27. Tập toán tửđột biến đầu tiên (dành cho Fortran)

Toán tử Diễn giải Mô tả

AAR array reference for array reference

replacement Thay thế các phần tử của mảng

ABS absolute value insertion Chèn hàm tính giá trị tuyệt đối

ACR array reference for constant replacement

Thay thế phần tử mảng cho các hằng số

AOR Arithmetic operator replacement Thay thế các toán tử số học

ASR array reference for scalar variable replacement

Thay thế các phần tử mảng cho các biến

CAR Constant for array reference replacement

Thay thế hằng số cho các phần tử mảng

CRP Constant replacement Thay thế hằng số

CSR Constant for scalar variable

replacement Thay thế hằng số cho các biến DER DO statement alterations Thay câu lệnh DO

DSA DATA statement alterations Thay đổi câu lệnh DATA GLR GOTO label replacement Thay thế nhãn lệnh GOTO LCR Logical connector replacement Thay thế các toán tử lo- gíc ROR Relational operator replacement Thay thế các toán tử quan hệ RSR RETURN statement replacement Thay thế câu lệnh RETURN SAN Statement analysis Phân tích câu lệnh

SAR Scalar variable for array reference replacement

Thay thế biến cho các phần tử mảng

SCR Scalar for constant replacement Thay thế biến cho các hằng số

SDL Statement deletion Xóa câu lệnh

SRC Source constant replacement Thay thế hằng số SVR Scalar variable replacement Thay thế biến

UOI Unary operator insertion Chèn thêm toán tử một ngôi

Đột biến bị diệt, đột biến còn sống và đột biến tương đương

Khi tiến hành thực thi lần lượt chương trình gốc P và đột biến P’ của P với một dữ liệu thử T, sẽ có hai kịch bản khác nhau có thể xảy ra:

- Một là, hoặc mỗi lỗi được chèn vào trong chương trình đột biến P’ được nhận biết, nghĩa là chương trình P và đột biến P’ cho ra kết quả khác nhau. Trong trường hợp này, đột biến P’ được gọi là bị diệt bởi dữ liệu thử T. Khi đó, T được gọi là dữ liệu thử thích hợp vì nó có khả năng phát hiện được sự khác nhau giữa chương trình gốc P và đột biến P’.

- Hai là, chương trình gốc P và đột biến P’ cho ra kết quả hoàn toàn giống nhau. Trong trường hợp này, có thể có hai khả năng xảy ra. Khả năng thứ nhất là dữ liệu thử T không đủ hiệu quả (hay được gọi là dữ liệu thử không thích hợp), chúng ta sẽ phải tiến hành thực hiện kiểm thử lại với các dữ liệu thử hiệu quả hơn. Khả năng thứ hai là chương trình P và đột biến P’ là những chương trình tương tự nhau, mọi dữ liệu thử đều không thể phân biệt được sự khác biết giữa chúng. Trong trường hợp này, P’ gọi là đột biến tương đương với chương trình gốc P. Trong cả hai trường hợp này, đột biến P’ được cho là còn sống.

Để áp dụng hiệu quả kiểm thử đột biến, việc phát hiện và loại bỏ các đột biến tương đương rất quan trọng. Có nhiều nghiên cứu đã được thực hiện nhằm phát hiện hiệu quả và tự động hóa việc phát hiện đột biến tương đương.

• Tỉ lệ đột biến

Tỉ lệ đột biến ( Mutation Score), được kí hiệu MS, của chương trình P và dữ liệu thử T là tỉ lệ các đột biến không tương đương (so với chương trình gốc) bị diệt bởi dữ liệu thử T, được mô tả bởi công thức sau:

MS( P,T) = D/N-E

trong đó, D là số đột biến đã bị diệt, N là tổng số các đột biến và E là số đột biến tương đương. Như vậy, 0<= MS<=1 hay 0%<MS%<100%.

Để đánh giá chất lượng của bộ dữ liệu thử, chúng ta dựa vào tỉ lệ đột biến. Tỉ lệ đột biến càng cao thì khả năng phân biệt các đột biến của bộ dữ liệu thử càng tốt. Như vậy, mục tiêu của kiểm thử đột biến là xây dựng bộ dữ liệu thử sao cho có thể diệt tất cả các đột biến không tương đương hay đạt tỉ lệ đột biến cao.

3.7.3. Quy trình kiểm thử đột biến

Kiểm thử đột biến được thực hiện qua nhiều bước khác nhau. Hình 4.19 minh họa quy trình kiểm thử đột biến. Trong quy trình này, các bước biểu diễn bởi nét liền là có thể tự động hóa được, trong khi các bước biểu diễn bằng nét đứt thường được xử lí thủ công. Gọi chương trình gốc là P, các đột biến là P’ và tập dữ liệu thử là T, quy trình kiểm tra thử đột biến gồm các bước sau:

Bước 1: Tạo đột biến P’ từ chương trình gốc P Bước 2: Tạo các dữ liệu thử T

Bước 3: Thực thi chương trình gốc là P với mỗi dữ liệu thử. Kiểm tra kết quả nhận được:

- Nếu đầu ra đúng thực hiện bước tiếp theo.

Bước 4: Thực thi từng đột biến còn sống với mỗi dữ liệu thử. So sánh kết quả thực hiện đột biến với kết quả thực hiện chương trình gốc đối với mỗi dữ liệu thử.

- Nếu tất cả các đột biến đều bị diệt, kết thúc quy trình. - Nếu còn đột biến chưa bị diệt, chuyển sang bước tiếp theo.

Bước 5: Phân tích và xác định các đột biến tương đương. Nếu còn các đột biến không tương đương nhưng chưa bị diệt thì các dữ liệu thử không đủ hiệu quả diệt đột biến. Phải hiệu chỉnh tập dữ liệu thử, vậy quay lại Bước 2.

Hình 3.27. Quy trình kiểm thử đột biến

3.7.4. Hạn chế của kiểm thử đột biến

Các nghiên cứu lí thuyết và kết quả thực nghiệm đã cho thấy rằng kiểm thử đột biến là phương pháp hiệu quả để đánh giá chất lượng của dữ liệu thử. Tuy nhiên, có một số hạn chế khi thực hiện khi thực hiện kiểm thử đột biến như sau:

- Việc nhận dạng các đột biến tương đương là rất quan trọng nhưng rất khó khăn, vì các đột biến tương đương hoạt động giống như chương trình gốc và trong quá trình kiểm thử những đột biến tương đương không thể bị diệt.

kiểm thử, được gọi là các đột biến không tương đương “ngoan cố” và rất khó trong việc diệt chúng.

- Chi phí tính toán trong kiểm thử đột biến rất cao, do số lượng toán tử đột biến thường rất lơn – các đoạn mã cần tạo đột biến nhiều nên sản sinh ra nhiều phiên bản đột biến. Như vậy, phải tạo ra một số lớn các đột biến cho một chương trình. Đồng thời việc thực hiện biên dịch, kiểm thử đối với tất cả các phiên bản đột biến chiếm chi phí tính toán lớn. Phân tích và đánh giá các đột biến cũng đòi hỏi chi phí đáng kể.

- Kiểm thử đột biến cũng tốn nhiều nhân công trong quá trình kiểm thử, nhất là việc xây dựng các dữ liệu thử đảm bảo diệt được tất cả các đột biến không tương đương.

Do vậy, có nhiều nghiên cứu nhằm nâng cao hiệu quả của kiểm thử đột biến như:

- Giảm chi phí phân tích các đột biến. Các kĩ thuật giảm chi phí này được nghiên cứu theo ba chiến lược: làm thông minh hơn, làm ít hơn và làm nhanh hơn. Chiến lượt thông minh hơn, gồm các kĩ thuật : đột biến yếu và kiến trúc phân tán. Chiến lươc làm ít hơn hướng đến lựa chọn những đột biến sao cho hiệu quả nhất nhưng vẫn đảm bảo chất lượng kiểm thử, gồm các kĩ thuật: đột biến lựa chọn và lấy mẫu đột biến. Chiến lược làm nhanh hơn gồm các kĩ thuật: thực thi đột biến dựa vào lược đồ và phương pháp tách rời biên dịch.

- Tự động hóa. Một số hoạt động trong quy trình kiểm thử đột biến được tự động hóa sẽ nâng cao hiệu quả của kiểm thử đột biến, như sinh dữ liệu tự động dựa trên rang buộc và phát hiện đột biến tương đương tự động.

3.7.5. Ứng dụng của kiểm thử đột biến

Kể từ khi ra đời (năm 1971), có nhiều công trình nghiên cứu phát triển hơn nữa về khả năng ứng dụng và làm cho kiểm thử đột biến trở thành một kĩ thuật kiểm thử thực tế và phổ biến.

Kiểm thử đột biến được áp dụng ở các hoạt động kiểm thử đơn vị và kiểm thử tích hợp. Kĩ thuật này được xem là kĩ thuật kiểm thử cấu trúc, đã được áp dụng cho nhiều ngôn ngữ lập trình khác nhau, như ngôn ngữ Fortran, ngôn ngữ ADA, các ngôn ngữ C/C++/C#, ngôn ngữ Java, ngôn ngữ VHDL, các lệnh truy vấn cơ sở dữ liệu SQL…

Ngoài việc áp dụng cho mã nguồn, kiểm thử đột biến còn được áp dụng ở mức thiết kế, để kiểm thử các đặc tả hay mô hình. Chẳng hạn, ở mức thiết kế, kiểm thử đột biến được áp dụng cho các máy trạng thái hữu hạn, mạng Petri, các dịch vụ Web…

Trong khuôn khổ của tài liệu này, chúng tôi chỉ trình bày lí thuyết cơ bản về kiểm thử đột biến. Bạn đọc quan tâm có thể tìm đọc them chi tiết trong tài liệu [5].

3.8. Kết luận

Các kỹ thuật kiểm thử chức năng được áp dụng rộng rãi và là hành trang không thể thiếu của những kiểm thử viên. Các kỹ thuật kiểm thử chức năng có thể được áp dụng ở tất cả các hoạt động kiểm thử đơn vị, kiểm thử tích hợp, kiểm thử hệ thống và kiểm thử chấp nhận. Có nhiều kỹ thuật kiểm thử chức năng khác nhau được nghiên cứu và áp dụng. Tuy nhiên, trong phạm vi tài liệu này, chúng ta chỉ tìm hiểu một số các kỹ thuật kiểm thử chức năng cơ bản. Mỗi kỹ thuật nhằm hướng đến phát hiện một lớp các loại lỗi khác nhau. Vì vậy, việc kết hợp các kỹ thuật này cho phép xây dựng tập các ca kiểm thử phát hiện nhiều loại lỗi khác nhau, tuy nhiên cũng không khẳng định được rằng phát hiện được tất cả các lỗi.

Các kĩ thuật kiểm thử cấu trúc dựa trên cấu trúc bên trong chương trình nhằm tạo ra dữ liệu phát hiện các lỗi lập trình. Kiểm thử cấu trúc thường chỉ áp dụng cho hoạt động kiểm thử đơn vị hay các chương trình nhỏ. Có nhiều kĩ thuật kiểm thử cấu trúc đã được nghiên cứu và áp dụng. Trong đó, các kĩ thuật kiểm thử dựa trên đồ thị được áp dụng phổ biến. Bên cạnh đó, cũng còn có nhiều kĩ thuật khác như kiểm thử đột biến, thực thi trừu tượng…Trong phạm vi của tài liệu này, chúng tôi chỉ trình bày các kĩ thuật được ứng dụng rộng rãi: Kiểm thử dựa trên đồ thị luồng điều khiển, kiểm thử dựa trên đồ thị luồng dữ liệu và kiểm thửđột biến.

Câu hi và bài tp

1. Giải thích các tiêu chí bao phủ dựa trên luồng dữ liệu điều khiển. 2. Độ đo McCabe có ý nghĩa như thế nào đối với kiểm thử viên? 3. Kiểm thử dựa trên đồ thị luồng dữ liệu nhằm phát hiện các lỗi gì? 4. Giải thích các tiêu chí bao phủ dựa trên đồ thị luồng dữ liệu. 5. Hãy cho biết mục đích của kiểm thử đột biến.

6. Giải thích hai giả thuyết lập trình viên giỏi và hiệu ứng liên kết trong kiểm thử đột biến.

7. Nêu các khó khăn của kiểm thử đột biến.

8. Xây dựng dữ liệu thử thỏa mãn tiêu chí bao phủ đỉnh và bao phủ cung cho đoạn mã nguồn sau:

Một phần của tài liệu Bài giảng kiểm thử phần mềm đh phạm văn đồng (Trang 95 - 104)