Basic Path Là Gì?
Thomas McCabe là người có công nảy ra ý tưởng kiểm thử đường dẫn cơ sở – basic path. Vào tháng 12 năm 1976, ông xuất bản bài báo “Một thước đo độ phức tạp” trên tạp chí IEEE Transactions on Software Engineering. Ông đưa ra giả thuyết rằng bất kỳ module phần mềm nào cũng có một số lượng nhỏ các đường dẫn độc lập, duy nhất (không bao gồm các bước lặp) xuyên qua nó. Ông gọi đây là những đường dẫn cơ sở – basic path. Lý thuyết cho rằng cấu trúc của code có thể được kiểm tra bằng cách thực thi thông qua số lượng đường dẫn nhỏ này và tất cả vô số đường dẫn khác nhau thực sự chỉ là sử dụng và tái sử dụng các đường dẫn cơ sở.
Đường dẫn cơ sở được xác định là đường dẫn độc lập duy nhất xuyên qua module – không cho phép lặp lại. Tập hợp đường dẫn cơ sở là số lượng đường dẫn cơ sở nhỏ nhất bao trùm cấu trúc của code.
Việc tạo một tập hợp các thử nghiệm bao gồm các đường dẫn cơ sở này, tập hợp cơ sở, sẽ đảm bảo cho chúng ta phạm vi bao quát của cả câu lệnh và quyết định về thử nghiệm. Đường dẫn cơ sở còn được gọi là đường dẫn tối thiểu để bao phủ.
Cyclomatic complexity Là Gì?
Độ phức tạp chu kỳ – Cyclomatic complexity là số vòng lặp cần thiết và không phải ngẫu nhiên số trường hợp kiểm thử mà chúng ta cần để kiểm thử tập hợp các đường dẫn cơ sở. Độ phức tạp không phụ thuộc vào kích thước của module mà phụ thuộc vào số lượng quyết định có trong đó.
McCabe, trong bài báo của mình, đã chỉ ra rằng độ phức tạp càng cao thì khả năng xảy ra số lượng lỗi càng cao. Các nghiên cứu sau đó chủ yếu cho thấy mối tương quan như vậy; các module có độ phức tạp cao nhất cũng có xu hướng chứa số lượng lỗi cao nhất. Vì code càng phức tạp thì càng khó hiểu và khó bảo trì. Do đó có thể đưa ra một lập luận hợp lý để giảm mức độ phức tạp. Đề xuất của McCabe là chia các module lớn hơn, phức tạp hơn thành các module nhỏ hơn, ít phức tạp hơn. Chúng ta có thể đo độ phức tạp theo chu kỳ bằng cách tạo biểu đồ luồng điều khiển có hướng. Điều này hoạt động tốt đối với các module nhỏ và chúng tôi sẽ thực hiện điều đó tiếp theo. Tuy nhiên, trong thực tế, các công cụ (tools) thường được sử dụng để đo độ phức tạp của module.
Công Thức Tính Cyclomatic Complexity
Hãy cùng mình xem xét hình dưới đây:

Hình: Ví dụ về Cyclomatic complexity
Ở phía bên trái, chúng ta có hàm tính ước số chung lớn nhất của hai số bằng thuật toán Euclid. Các đường chấm từ code đến sơ đồ luồng McCabe ở giữa hình cho thấy các chuỗi không phân nhánh của 0 hoặc nhiều câu lệnh trở thành các cạnh (mũi tên) và cách các cấu trúc phân nhánh và lặp trở thành các nút (bubbles). Ở phía bên phải của hình, bạn thấy cách tính Cyclomatic Complexity.
Cách 1: C = #R + 1
Cách 2: C = #E – #N +2
Số liệu độ phức tạp theo chu kỳ của McCabe. Có vẻ đơn giản nhất có lẽ là phép tính “enclosed region”. Bốn vùng kèm theo (R1, R2, R3, R4), được biểu thị bằng R trong phương trình trên, được tìm thấy trong sơ đồ bằng cách lưu ý rằng mỗi quyết định (bubbles) có hai nhánh, trên thực tế, bao quanh một vùng của biểu đồ. Phương pháp tính toán khác bao gồm việc đếm các cạnh (mũi tên) và các nút (bubbles) và áp dụng các giá trị đó vào phép tính, E – N + 2, trong đó E là số cạnh và N là số nút.
Đối với các hàm lớn hơn, việc vẽ biểu đồ và thực hiện phép tính từ nó có thể thực sự khó khăn. Vì vậy, một nguyên tắc đơn giản là: Đếm các cấu trúc phân nhánh và lặp rồi cộng 1. Các câu lệnh if và các cấu trúc for, while và do/while, mỗi câu lệnh được tính là một. Đối với cấu trúc switch/case, mỗi khối case được tính là một. Trong cấu trúc if và ladder, cái khác không được tính. Đối với cấu trúc switch/case, khối default không được tính. Đây là một quy tắc chung, nhưng nó thường có vẻ hiệu quả. Trong code mẫu, có ba câu lệnh if và một câu lệnh while. Do đó C = 3 + 1 + 1 = 5.
Hạn Chế/ Khó Khăn
Kiểm thử đường dẫn – Path Testing có hiệu quả hạn chế vì những lý do sau:
- Lập kế hoạch bao phủ không có nghĩa là bạn sẽ bao phủ được – đặc biệt khi có lỗi.
- Nó không thể hiện chức năng hoàn toàn sai hoặc thiếu.
- Lỗi giao diện giữa các module sẽ không xuất hiện trong quá trình kiểm thử đơn vị.
- Lỗi cơ sở dữ liệu và luồng dữ liệu có thể không được phát hiện.
- Tương tác không chính xác với các module khác sẽ không bị phát hiện trong quá trình kiểm thử đơn vị.
- Không phải tất cả các lỗi khởi tạo đều có thể được phát hiện bằng thử nghiệm luồng điều khiển.
- Các lỗi về yêu cầu và đặc tả sẽ không bị phát hiện trong quá trình kiểm thử đơn vị.
Tạo sơ đồ, chọn một tập hợp các đường dẫn bao phủ, tìm các giá trị dữ liệu đầu vào để buộc các đường dẫn đó, thiết lập các trường hợp vòng lặp và kết hợp – đó là rất nhiều công việc. Có lẽ cần nhiều công sức để thiết kế quy trình và chắc chắn nhiều công việc hơn là viết code cho nó. Số liệu thống kê chỉ ra rằng bạn sẽ dành một nửa thời gian để kiểm tra và gỡ lỗi – có lẽ thời gian đó bao gồm thời gian cần thiết để thiết kế và ghi lại các trường hợp kiểm thử.
Mình xin dừng bài viết hôm nay ở đây. Hẹn gặp lại các bạn trong các bài viết tiếp theo.
Happy Testing!