ỨNG DỤNG KỸ THUẬT KIỂM THỬ ĐỘT BIẾN ĐỂ KIỂM THỬ CÁC CHƯƠNG TRÌNH C-SHARP APPLYING MUTATION TESTING TO C-SHARP PROGRAM TESTS Nguy ễn Thanh Bình Trường Đại học Bách khoa, Đại học Đà Nẵng
Trang 1ỨNG DỤNG KỸ THUẬT KIỂM THỬ ĐỘT BIẾN
ĐỂ KIỂM THỬ CÁC CHƯƠNG TRÌNH C-SHARP
APPLYING MUTATION TESTING TO C-SHARP PROGRAM TESTS
Nguy ễn Thanh Bình
Trường Đại học Bách khoa, Đại học Đà Nẵng
Nguy ễn Quang Vũ
Trường CĐ CNTT Hữu nghị Việt Hàn
TÓM T ẮT
Ki ểm thử phần mềm luôn là một trong những hoạt động quan trọng nhằm đánh giá chất
lượng phần mềm Một trong những kỹ thuật kiểm thử có khả năng tự động hóa cao là kỹ thuật
ki ểm thử đột biến (mutation testing) Bài báo trình bày ứng dụng kỹ thuật kiểm thử đột biến
trong việc kiểm thử các chương trình được phát triển bởi ngôn ngữ lập trình C-Sharp Kỹ thuật
kiểm thử đột biến được trình bày và phân tích các hạn chế, cũng như các phương pháp cải
ti ến Từ đó, một quy trình kiểm thử các chương trình C-Sharp ứng dụng kiểm thử đột biến sử
d ụng các công cụ Nester và Nunit được đề xuất Bài báo minh họa một ứng dụng cụ thể cho
th ấy kết quả khả quan Kết quả của bài báo có thể áp dụng vào các quy trình kiểm thử trong
các đơn vị phát triển phần mềm
ABSTRACT
Software testing is always one of the important activities in order to evaluate the
software quality One of the testing techniques with high automation is mutation testing This
paper presents the application of mutation testing to testing programs developed by C-Sharp
language Thus, mutation testing is introduced, its limitations and some methods for
improvement are also analyzed Then, a testing process for C-Sharp programs applying
mutation testing using Nester and Nunit tools is proposed The paper also shows some
promising experimental results This approach can be applied to testing processes of software
development companies
1 Đặt vấn đề
Kiểm thử phần mềm là một trong những hoạt động quan trọng trong tiến trình
phát triển phần mềm Nó góp một phần rất lớn trong việc đánh giá chất lượng của một
phần mềm và là qui trình bắt buộc trong các dự án phát triển phần mềm trên thế giới
cũng như trong nước
Tuy nhiên, hoạt động kiểm thử thường gặp nhiều khó khăn Thứ nhất, kiểm thử
các hệ thống phức tạp đòi hỏi rất nhiều nguồn tài nguyên và chi phí cao Thứ hai, tiến
trình phát triển phần mềm luôn trải qua nhiều hoạt động biến đổi thông tin, sự mất mát
thông tin trong quá trình biến đổi là yếu tố chính làm cho hoạt động kiểm thử khó khăn
Thứ ba, kiểm thử chưa được chú trọng trong đào tạo con người Cuối cùng, không tồn
tại kỹ thuật kiểm thử cho phép khẳng định một phần mềm hoàn toàn đúng đắn hay
không chứa lỗi
Trang 2Với mục đích phát hiện lỗi, kiểm thử phần mềm thường phải trãi qua các bước:
tạo dữ liệu thử, thực thi phần mềm trên dữ liệu thử và quan sát kết quả nhận được Trong các bước này, bước tạo dữ liệu đóng vai trò quan trọng nhất, bởi vì chúng ta không thể tạo ra mọi dữ liệu từ miền vào của chương trình, mà chúng ta chỉ có thể tạo ra các dữ liệu thử có khả năng phát hiện lỗi cao nhất Vấn đề đặt ra là làm sao để đánh giá được khả năng phát hiện lỗi của một bộ dữ liệu thử ? Chính kỹ thuật kiểm thử đột biến
là câu trả lời Kỹ thuật này cho phép đánh giá chất lượng (khả năng phát hiện lỗi) của
một bộ dữ liệu thử Trong bài báo này chúng tôi sẽ tập trung vào vấn đề đánh giá chất
lượng của các bộ dữ liệu thử dùng để kiểm thử các chương trình C-Sharp
2 K ỹ thuật kiểm thử đột biến
2.1 Khái ni ệm
Kiểm thử đột biến (mutation testing) được đề xuất đầu tiên năm 1978 bởi DeMillo [5], và được thiết kế để tạo ra một bộ dữ liệu kiểm thử hiệu quả có khả năng phát hiện lỗi của chương trình
Kiểm thử đột biến tập trung vào việc đánh giá khả năng phát hiện lỗi của dữ liệu dùng để kiểm thử Kiểm thử đột biến được dùng kết hợp với các kỹ thuật kiểm thử thông thường nhưng không thể được dùng để thay thế cho các kỹ thuật kiểm thử thông thường đó
Kiểm thử đột biến là một kỹ thuật kiểm thử hộp trắng hay kiểm th ử cấu trúc, được xây dựng dựa vào hai giả thuyết cơ bản [4]: giả thuyết “lập trình viên giỏi” (competent programmer) và giả thuyết “hiệu ứng liên kết” (coupling effect) Giả thuyết
“lập trình viên giỏi” giả thiết rằng lập trình viên chỉ phạm những lỗi đơn giản do sơ
suất Giả thuyết “hiệu ứng liên kết” giả thuyết rằng, nếu dữ liệu thử phát hiện được các
lỗi đơn giản thì dữ liệu đó cũng cho phép phát hiện các lỗi phức tạp
Kiểm thử đột biến bao gồm việc tạo ra các phiên bản lỗi của chương trình gốc
được kiểm thử nhờ vào các toán tử đột biến Các phiên bản lỗi đó được gọi là các đột
bi ến (mutant)
Hình 1 Một ví dụ về đột biến
Trang 3Toá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 đột biến Các toán tử đột biến được xác định bởi ngôn ngữ của chương trình được kiểm thử và hệ thống đột biến được dùng để kiểm thử
Khi tiến hành thực thi kiểm thử 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 kiểm thử T, sẽ có hai kịch bản khác nhau có thể xảy ra:
- Một là, đột biến P’ được gọi là bị diệt bởi dữ liệu kiểm thử T
- 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,
đột biến P’ được cho là còn sống
Các đột biến tương đương (equivalent mutant) là các đột biến của chương trình
gốc nhưng hoạt động hoàn toàn giống với chương trình gốc và cho ra kết quả giống với chương trình gốc trong mọi trường hợp kiểm thử
Tỷ số MS = 100 * D/(N - E) được gọi là tỷ lệ đột biến (Mutation Score - MS) Trong đó, D là đột biến đã bị diệt; N là tổng số các đột biến; E là số đột biến tương
đương Tỷ lệ đột biến cho phép đánh giá chất lượng bộ dữ liệu thử
2.2 Thu ật toán kiểm thử đột biến
Thuật toán kiểm thử đột biến [4] gồm các bước cơ bản sau:
Bước 1: Sản sinh đột biến (dùng công cụ sản sinh tự động hoặc sản sinh thủ
công) từ chương trình gốc
Bước 2: Sản sinh các dữ liệu kiểm thử
Bước 3: Thực hiện từng dữ liệu kiểm thử với chương trình gốc
Bước 3.1: Nếu kết quả không đúng, phải chỉnh sửa chương trình và
kiểm thử lại
Bước 3.2: Nếu kết quả đúng, thực hiện bước tiếp theo
Bước 4: Thực hiện từng dữ liệu kiểm thử với từng đột biến còn sống
Bước 4.1: Nếu kết quả ra của đột biến khác với chương trình gốc,
chương trình đột biến được xem là k hông đúng và bị diệt Hoàn thành
kiểm thử
Bước 4.2: Nếu đột biến sống sót được (qua kiểm thử): phân tích các đột
biến còn sống Có hai khả năng xảy ra:
- Hoặc các đột biến là đột biến tương đương: không thể bị diệt
- Hoặc có thể diệt các đột biến được nhưng các dữ liệu kiểm thử không đủ mạnh để diệt đột biến Do đó phải tạo ra các dữ liệu
kiểm thử khác và lặp lại bước 1
2.3 Hạn chế của kỹ thuật kiểm thử đột biến
Kỹ thuật kiểm thử đột biến rất hiệu quả trong việc đánh giá chất lượng dữ liệu
thử và dễ dàng tự động hóa Tuy nhiên, kỹ thuật này có một số hạn chế Thứ nhất, 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 để thực hiện
Trang 4nhận dạng chúng Thứ hai, một số các đột biến không tương đương nhưng vẫn còn tồn
tại, đượ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 Cuối cùng, “chi phí tính toán” của kiểm thử đột biến rất cao
3 Các c ải tiến kỹ thuật kiểm thử đột biến
Nhằm nâng cao hiệu quả của kỹ thuật kiểm thử đột biến, một số cải tiến đã được
đề xuất [1, 3, 7, 8, 9,10]
3.1 Đột biến yếu
Đột biến yếu (weak mutation), được đề nghị bởi Howden [10], như là một sự cải
tiến và mở rộng của kiểm thử đột biến Ý tưởng chính của đột biến yếu như sau: Trong thuật ngữ của Howden, P là một chương trình, C là một thành phần của P, C’ là một
phiên bản đột biến của C, và P’ có chứa C’ là một phiên bản đột biến của P Kiểm thử đột biến yếu chỉ đòi hỏi một dữ liệu kiểm thử T phải làm cho C’ tính toán ra một giá trị
sai khác so với giá trị được tính toán bởi C.
3.2 Phân tích đột biến dựa vào giản đồ
Một kỹ thuật mới để thực hiện phân tích đột biến sử dụng các giản đồ chương trình [6, 7] (program schemata), cho phép mã hoá tất cả các đột biến của chương trình vào một siêu chương trình (meta-program) Sau đó, siêu chương trình này được biên
dịch và chạy với tốc độ cao hơn, so với việc biên dịch và thực thi từng đột biến riêng lẻ
3.3 Đột biến lựa chọn
Do số lượng đột biến được sản sinh ra bởi các toán tử đột biến thường là rất lớn, nên Mathur [1] đã đề xuất phương pháp đột biến lựa chọn (selective mutation) Đó là phương pháp cho phép lựa chọn trước tập các toán tử có thể sinh ra đột biến Ý tưởng này nhằm làm cho các đột biến được sản sinh ra thật sự khác biệt với các đột biến khác [2, 3] Điều đó làm giảm số lượng các đột biến được sản sinh ra
3.4 Đột biến lạc quan
Một trong những bước thực hiện thủ công rất khó khăn của việc dùng hệ thống
kiểm thử đột biến là việc xác định các đột biến tương đương Có một vài đột biến có thể
bị diệt nhưng đã không bị diệt, và có thể gần như chúng bị bỏ quên Do đó, kiểm thử viên phải hết sức chú ý để phát hiện các đột biến tương đương thông qua tập dữ liệu thử
3.5 S ản sinh dữ liệu kiểm thử dựa vào ràng buộc
Phương pháp sản sinh dữ liệu kiểm thử dựa vào ràng buộc [8] gồm một tập các
thủ tục được thiết kế để tạo dữ liệu thử thoả mãn kiểm thử đột biến Phương pháp này yêu cầu một dữ liệu kiểm thử diệt được đột biến phải thoả mãn ba điều kiện: điều kiện
có thể đạt đến được, điều kiện cần và điều kiện đủ Điều kiện có thể đạt đến được là các câu lệnh đã bị biến đổi trong các đột biến phải được kích hoạt khi kiểm thử Điều kiện
cần là khi một câu lệnh bị biến đổi được thực thi, thì dữ liệu kiểm thử phải làm cho chương trình đột biến chạy sai, nghĩa là lỗi đã được chèn vào trong chương trình phải
tạo ra trạng thái lỗi cho các hoạt động của chương trình Điều kiện đủ là các sai sót đó
phải được truyền đến các tính toán của chương trình để cho ra kết quả sai
Trang 54 Ứng dụng kỹ thuật kiểm thử đột biến để kiểm thử các chương trình C-Sharp
Gần đây, ngôn ngữ C-Sharp trong môi trường NET là một trong ngôn ngữ được
sử dụng rộng rãi để phát triển các ứng dụng Trong bài báo này, chúng tôi đề xuất quy trình áp dụng kỹ thuật kiểm thử đột biến cho các ứng dụng được phát triển dùng C-Sharp
Quy trình ứng dụng kiểm thử đột biến để kiểm thử các chương trình C-Sharp áp
dụng kỹ thuật kiểm thử đột biến lựa chọn và sử dụng công cụ Nester, dùng để phân tích
và tạo đột biến, và công cụ Nunit dùng để kiểm thử đơn vị Quy trình này được minh
họa trong Hình 2
Chúng tôi tiến hành kiểm thử một chương trình cs-money được viết bằng ngôn
ngữ C-Sharp gồm có các lớp, như: AssemblyInfo.cs, Imoney.cs, Money.cs, MoneyBag.cs, gồm khoảng 200 dòng lệnh và 21 trường hợp kiểm thử cùng dữ liệu thử được xây dựng trong MoneyTest.cs
Trước hết, chúng ta sẽ kiểm thử chương trình này bằng bộ kiểm thử Nunit (phiên bản 2.2.0), với các trường hợp kiểm thử và dữ liệu thử được thiết kế sẵn đó, kết
quả sẽ được mô tả như trong Hình 3
Tốt
Không t ốt Tốt
Không tốt
NESTER Đột biến P’
Gọi lệnh biên dịch
Hình 2 Quy trình ứng dụng kỹ thuật kiểm thử đột biến
Rõ ràng, đây là một chương trình tốt dưới “góc nhìn” của Nunit với dữ liệu thử được xây dựng trong 21 trường hợp kiểm thử đó
Trang 6Hình 3 Kết quả kiểm thử bằng Nunit 2.2.0
Tiếp theo, chúng ta sử dụng Nester với tập toán tử đột biến được lựa chọn để
thực hiện đột biến Tập toán tử đột biến được lựa chọn gồm: {true, false}, {+,-}, {==,!=}, {if(,if(true}, {xyz, a b c, 12, <> ?}, {1, 2, 3, 4}, {a, b, c, d} Đây là các toán tử
có xuất hiện trong chương trình và có thể bị “viết nhầm” bởi các lập trình viên
Trong quá trình thực thi, Nester sinh ra số các đột biến là 78 và trong đó có 70 đột biến bị diệt và 8 đột biến “còn sống” Tỷ lệ đột biến ở đây là xấp xỉ 90% Cụ thể với
từng trường hợp kiểm thử được cho trong Bảng 1
B ảng 1 - Chất lượng các trường hợp kiểm thử chương trình cs-money sau khi thực thi Nester
Trường hợp kiểm thử S ố đột biến diệt được S ố đột biến không
di ệt được
Trang 711 MoneyHash 76 2
Điều này chứng tỏ, chất lượng bộ dữ liệu thử mà các kiểm thử viên tạo ra trong
21 trường hợp kiểm thử ở trên rõ ràng là chưa cao, vì không có bất kỳ một trường hợp
kiểm thử nào diệt được tất cả các đột biến Đặc biệt, 4 đột biến được sinh ra khi Nester
“chèn lỗi” vào lớp AssemlyInfo.cs, thì không có bất cứ trường hợp kiểm thử nào diệt được Như vậy, Nester đã đưa ra được một cảnh báo rất kịp thời để các kiểm thử viên xem xét và xây dựng lại các trường hợp kiểm thử và bộ dữ liệu thử tốt hơn để đảm bảo
chất lượng của phần mềm
5 K ết luận
Một sản phẩm phần mềm không chỉ đơn giản là các đoạn mã chương trình, mà
nó còn bao gồm nhiều thành phần với nhiều các vai trò khác nhau Do đó, việc xảy ra các lỗi phần mềm không chỉ ở công đoạn lập trình, mà còn xảy ra ở tất cả các công đoạn khác nhau của quy trình phát triển phần mềm, với xác suất cao thấp khác n hau Kiểm
thử là một giai đoạn đóng vai trò rất quan trọng, quyết định đến việc đánh giá chất lượng của một sản phẩm phần mềm Mục đích của kiểm thử là đảm bảo rằng tất cả các thành phần của phần mềm ăn khớp, vận hành như mong đợi và phù hợp các tiêu chuẩn thiết kế
Kiểm thử đột biến được giới thiệu như là một ý tưởng để đánh giá chất lượng
của các bộ dữ liệu kiểm thử Dựa vào các ưu điểm, nhược điểm của kỹ thuật kiểm thử đột biến, có các phương pháp nhằm cải tiến kỹ thuật kiểm thử đột biến , như: đột biến
yếu, đột biến lựa chọn, đột biến lạc quan Bài báo đề xuất và xây dựng một giải pháp
kiểm thử các chương trình C-Sharp hiệu quả, giảm chi phí và thời gian
Hiện nay, cho dù vấn đề kiểm thử phần mềm đã được chú trọng đầu tư và quan tâm nhiều trong suốt tiến trình phát triển sản phẩm phần mềm Tuy nhiên, vấn đề chất
Trang 8lượng của các bộ dữ liệu kiểm thử gần như chưa được đánh giá một cách chính xác, điều đó góp phần làm giảm đi chất lượng và hiệu quả của các sản phẩm phần mềm Đặc
biệt là trong thời điểm Việt Nam đang mong muốn xây dựng một ngành công nghiệp
phần mềm Do đó, việc tạo điều kiện thuận lợi để nghiên cứu và ứng dụng kỹ thuật
kiểm thử đột biến vào thực tế sẽ góp phần rất lớn trong việc nâng cao chất lượng các sản
phẩm phần mềm
TÀI LIỆU THAM KHẢO
[1] A.P Mathur (1991), Performance, effectiveness and reliability issues in software testing,
Tokyo, Japan
[2] Jeff Offutt, Ammei Lee, Gregg Rothermel, Roland H Untch, and Christian Zapf (1996), An Experimental Determination of Sufficient Mutant Operators, George Mason University [3] Jeff Offutt, Gregg Rothermel, Roland H Untch, and Christian Zapf (1993), An Experimental Evaluation of Selective Mutation, Baltimore, MD
[4] Mark Harman and Rob Hierons (2006), “An Overview of Mutation Testing”, Genetic Algorithms for Mutation Testing, Brunel University, London
[5] R.A DeMillo and A.J Offutt (1993), Experimental results from an automatic test case generator, ACM transactions on Softwar Engineering Methodology, 2(2) pages 109-127 [6] R.Untch (1992), “Mutation-based software testing using program schemata”, Proceedings of
30 th
[7] R Untch, A.J Offutt and M.J Harold (1993), Mutation Analysis using program schemate,
pages 139-148, Cambridge, MA
ACM Southeast Regional Conference, Raleigh, NC
[8] T.A Budd (1980), Mutation Analysis of Program Test Data, Ph.D Thesis, Yale University,
New Haven CT
[9] Nguyen Thanh Binh, C Robach (2001), “Mutation Testing Applied to Hardware: the
Mutants Genenration”, Proceedings of the 11th IFIP International Conference on Very Large Scale Integration,118 123, Montpellier, France
[10] W.E Howden (1982), Weak mutation testing and completeness of test sets, IEEE Transactions on Software Engineering, 8(4) pages 371-379