TẠP CHÍ KHOA HỌC VÀ CÔNG NGHỆ, ĐẠI HỌC ĐÀ NẴNG - SỐ 5(34).2009
8
Ứ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.
TẠP CHÍ KHOA HỌC VÀ CÔNG NGHỆ, ĐẠI HỌC ĐÀ NẴNG - SỐ 5(34).2009
9
Vớ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
TẠP CHÍ KHOA HỌC VÀ CÔNG NGHỆ, ĐẠI HỌC ĐÀ NẴNG - SỐ 5(34).2009
10
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 độ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à khô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
TẠP CHÍ KHOA HỌC VÀ CÔNG NGHỆ, ĐẠI HỌC ĐÀ NẴNG - SỐ 5(34).2009
11
nhậ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.
TẠP CHÍ KHOA HỌC VÀ CÔNG NGHỆ, ĐẠI HỌC ĐÀ NẴNG - SỐ 5(34).2009
12
4. Ứ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
Chương t rình P
Nunit 2.2.0
Chỉnh sửa P
Tốt ?
NESTER
Đột biế
n P’
Gọi lệnh biên dịch
Nunit 2.2.0
KẾT QUẢ
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ử đó.
TẠP CHÍ KHOA HỌC VÀ CÔNG NGHỆ, ĐẠI HỌC ĐÀ NẴNG - SỐ 5(34).2009
13
Hì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
1. BagMultiply 67 11
2. BagNegate 71 7
3. BagSimpleAdd 68 10
4. BagSubtract 67 11
5. BagSumAdd 68 10
6. IsZero 68 10
7. MixedSimpleAdd 71 7
8. MoneyBagEquals 71 7
9. MoneyBagHash 76 2
10. MoneyEquals 73 5
TẠP CHÍ KHOA HỌC VÀ CÔNG NGHỆ, ĐẠI HỌC ĐÀ NẴNG - SỐ 5(34).2009
14
11. MoneyHash 76 2
12. Normalize 71 7
13. Normalize2 68 10
14. Normalize3 66 12
15. Normalize4 67 11
16. Print 76 2
17. SimpleAdd 74 4
18. SimpleBagAdd 68 10
19. SimpleMultiply 75 3
20. SimpleNegate 74 4
21. SimpleSubtract 73 5
Đ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
TẠP CHÍ KHOA HỌC VÀ CÔNG NGHỆ, ĐẠI HỌC ĐÀ NẴNG - SỐ 5(34).2009
15
lượ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.