Độ phức tạp Cyclomatic trong kiểm thử phần mềm kèm ví dụ
⚡ Tóm tắt thông minh
Độ phức tạp chu trình (Cyclomatic Complexity) là một chỉ số phần mềm được Thomas McCabe phát triển vào năm 1976, dùng để đếm số lượng các đường dẫn độc lập trong một chương trình. Nó được tính toán từ đồ thị luồng điều khiển và cho biết số lượng trường hợp kiểm thử cần thiết để đạt được độ phủ nhánh đầy đủ.

Độ phức tạp Cyclomatic của McCabe là gì?
Độ phức tạp theo chu kỳ trong kiểm thử phần mềm là một phép đo kiểm tra được sử dụng để đo độ phức tạp của một chương trình phần mềm. Đây là phép đo định lượng các đường dẫn độc lập trong mã nguồn của một chương trình phần mềm. Độ phức tạp theo chu kỳ có thể được tính bằng cách sử dụng biểu đồ luồng điều khiển hoặc liên quan đến các hàm, mô-đun, phương pháp hoặc lớp trong một chương trình phần mềm.
Đường đi độc lập được định nghĩa là đường đi có ít nhất một cạnh chưa được đi qua trước đó trong bất kỳ đường đi nào khác.
Số liệu này được Thomas J. McCabe phát triển vào năm 1976 và nó dựa trên cách trình bày luồng điều khiển của chương trình. Luồng điều khiển mô tả chương trình dưới dạng biểu đồ bao gồm Nút và Cạnh.
Trong biểu đồ, các Nút biểu thị các tác vụ xử lý trong khi các cạnh biểu thị luồng điều khiển giữa các nút.
Ký hiệu đồ thị luồng cho một chương trình
Ký hiệu Biểu đồ luồng cho một chương trình xác định một số nút được kết nối qua các cạnh. Dưới đây là sơ đồ luồng cho các câu lệnh như if-else, While, cho đến khi và trình tự luồng thông thường.
Cách tính độ phức tạp Cyclomatic
Biểu diễn toán học:
Về mặt toán học, đó là tập hợp các đường đi độc lập xuyên qua sơ đồ đồ thị. Code Độ phức tạp của chương trình có thể được xác định bằng công thức –
V(G) = E - N + 2
Ở đâu,
E – Số cạnh
N – Số lượng nút
V (G) = P + 1
Trong đó P = Số nút vị ngữ (nút chứa điều kiện)
Thí dụ -
i = 0; n=4; //N-Number of nodes present in the graph while (i<n-1) do j = i + 1; while (j<n) do if A[i]<A[j] then swap(A[i], A[j]); end do; j=j+1; end do;
Biểu đồ luồng cho chương trình này sẽ là
Tính toán theo phương pháp toán học,
- V(G) = 9 – 7 + 2 = 4
- V(G) = 3 + 1 = 4 (Nút điều kiện là 1,2 và 3 nút)
Bộ cơ sở, bốn con đường thực thi độc lập:
- 1, 7
- 1, 2, 6, 1, 7
- 1, 2, 3, 4, 5, 2, 6, 1, 7
- 1, 2, 3, 5, 2, 6, 1, 7
Tính chất của độ phức tạp chu trình
Sau đây là các tính chất của độ phức tạp Cyclomatic:
- V(G) là số đường đi độc lập tối đa trong đồ thị
- V(G) >=1
- G sẽ có một đường đi nếu V(G) = 1
- Một nguyên tắc thường được sử dụng là giữ V(G) ở mức 10 hoặc thấp hơn cho một mô-đun đơn lẻ.
Chỉ số này hữu ích như thế nào đối với việc kiểm thử phần mềm?
Kiểm thử đường dẫn cơ sở là một trong những kỹ thuật kiểm thử hộp trắng và nó đảm bảo thực thi ít nhất một câu lệnh trong quá trình kiểm thử. Nó kiểm tra từng đường dẫn độc lập tuyến tính trong chương trình, có nghĩa là... Số lượng trường hợp kiểm thử cần thiết bằng độ phức tạp chu trình của chương trình..
Đo lường này hữu ích vì các đặc tính của Độ phức tạp Cyclomatic (M) –
- M có thể là số ca kiểm thử để đạt được phạm vi bao phủ nhánh (Giới hạn trên)
- M có thể là số đường đi qua đồ thị. (Chặn dưới)
Hãy xem xét ví dụ này –
If (Condition 1) Statement 1 Else Statement 2 If (Condition 2) Statement 3 Else Statement 4
Độ phức tạp theo chu kỳ cho chương trình này sẽ là 8-7+2=3.
Vì độ phức tạp được tính là 3, nên cần có ba trường hợp thử nghiệm để có thể bao phủ toàn bộ đường dẫn cho ví dụ trên.
Các bước cần tuân theo
Cần thực hiện theo các bước sau để tính toán độ phức tạp Cyclomatic và thiết kế trường hợp thử nghiệm.
Bước 1 – Xây dựng đồ thị với các nút và cạnh từ mã
Bước 2 – Xác định các đường dẫn độc lập
Bước 3 – Tính toán độ phức tạp Cyclomatic
Bước 4 – Thiết kế các trường hợp thử nghiệm
Khi tập hợp cơ bản được hình thành, CÁC TRƯỜNG HỢP KIỂM TRA nên được viết để thực hiện tất cả các đường dẫn.
Thông tin thêm về V (G)
Độ phức tạp của chu kỳ có thể được tính toán thủ công nếu chương trình nhỏ. Các công cụ tự động cần được sử dụng nếu chương trình rất phức tạp vì điều này liên quan đến nhiều biểu đồ luồng hơn. Dựa trên số độ phức tạp, nhóm có thể kết luận về các hành động cần thực hiện để đo lường.
Bảng sau đây cung cấp tổng quan về số phức tạp và ý nghĩa tương ứng của v (G):
| Số phức tạp | Ý nghĩa |
|---|---|
| 1 để 10 |
Mã nguồn được cấu trúc tốt và viết mạch lạc. Khả năng kiểm tra cao Chi phí và công sức ít hơn |
| 11 để 20 |
Mã phức tạp Khả năng kiểm thử trung bình Chi phí và công sức ở mức trung bình |
| 21 để 40 |
Mã rất phức tạp Khả năng kiểm thử thấp Chi phí và công sức bỏ ra rất cao. |
| > 40 |
Hoàn toàn không thể kiểm chứng được Chi phí và công sức rất cao |
Công cụ tính toán độ phức tạp chu trình
Có nhiều công cụ để xác định độ phức tạp của ứng dụng. Một số công cụ tính toán độ phức tạp được sử dụng cho các công nghệ cụ thể. Độ phức tạp có thể được tìm thấy bằng số điểm quyết định trong một chương trình. Các điểm quyết định là if, for, for-each, while, do, catch, case trong mã nguồn.
Ví dụ về các công cụ là
- OCLint – Trình phân tích mã tĩnh cho C và các ngôn ngữ liên quan
- SonarQube – Báo cáo độ phức tạp chu trình và nhận thức trên hơn 25 ngôn ngữ
- Visual Studio Code Số liệu – Phân tích độ phức tạp chu trình tích hợp sẵn cho các assembly .NET
- Radon và Lizard – Các công cụ phân tích độ phức tạp dòng lệnh dành cho Python và cho các dự án đa ngôn ngữ tương ứng
- GMetrics – Tìm số liệu trong Java ứng dụng liên quan
Ứng dụng của độ phức tạp chu trình
Độ phức tạp của chu kỳ có thể chứng minh là rất hữu ích trong
- Giúp các nhà phát triển và người thử nghiệm xác định việc thực thi đường dẫn độc lập
- Các nhà phát triển có thể đảm bảo rằng tất cả các đường dẫn đã được kiểm tra ít nhất một lần.
- Giúp chúng ta tập trung hơn vào những con đường chưa được khám phá
- Cải thiện phạm vi bao phủ mã trong Kỹ thuật phần mềm
- Đánh giá rủi ro liên quan đến ứng dụng hoặc chương trình
- Sử dụng các số liệu này sớm trong chu kỳ sẽ giảm bớt rủi ro cho chương trình
Cách giảm độ phức tạp của chu trình
Chỉ số độ phức tạp cao là một tín hiệu, chứ không phải là một phán quyết. Bốn lần tái cấu trúc chiếm phần lớn mức giảm độ phức tạp có thể đạt được trong thực tế.
- Extracphương pháp t. Việc tách một nhánh thành một hàm riêng biệt sẽ phân chia độ phức tạp giữa hai mô-đun. Tổng độ phức tạp của toàn hệ thống không thay đổi, nhưng mỗi đơn vị trở nên có thể kiểm thử độc lập.
- Thay thế chuỗi điều kiện bằng một câu lệnh tra cứu. Một chuỗi câu lệnh if-else-if dài kiểm tra cùng một biến sẽ trở thành một cấu trúc map hoặc switch, giúp thu gọn nhiều điểm quyết định thành một.
- Hãy sử dụng các điều khoản bảo vệ. Việc trả về sớm khi nhận được đầu vào không hợp lệ sẽ loại bỏ sự lồng ghép mà một khối if-else lớn duy nhất tạo ra, mà không làm thay đổi hành vi.
- Thay thế các câu lệnh điều kiện bằng đa hình. Trong trường hợp câu lệnh điều kiện chuyển đổi dựa trên kiểu dữ liệu, việc tách mỗi nhánh thành một lớp riêng biệt sẽ loại bỏ hoàn toàn quyết định đó.
Trước đây, với V(G) = 4:
if (user != null) { if (user.isActive()) { if (user.hasRole("admin")) { return grantAccess(); } } } return denyAccess();
Sau đó, với cùng hành vi đó nhưng đã loại bỏ cấu trúc lồng nhau:
if (user == null) return denyAccess(); if (!user.isActive()) return denyAccess(); if (!user.hasRole("admin")) return denyAccess(); return grantAccess();
Một lưu ý về chỉ số này. Độ phức tạp chu trình đếm số quyết định, chứ không phải độ khó. Một câu lệnh switch với hai mươi trường hợp đơn giản đạt điểm 21 nhưng vẫn dễ đọc, trong khi một khối lồng nhau sâu đạt điểm 8 có thể khó hiểu hơn nhiều. Hãy sử dụng con số này để tìm ra các ứng viên cần xem xét lại, chứ không phải là mục tiêu để gian lận.


.png)
.png)