Độ đo Chidamber và Kemerer
Chidamber và Kemerer [23] cho rằng các độ đo trước đó chủ yếu dùng cho các thiết kế phần mềm có cấu trúc và không đáp ứng tốt yêu cầu về đo lường phần mềm. Các hạn chế của các độ đo phần mềm trước gồm: thiếu lý thuyết cơ sở, thiếu thuộc tính đo lường phù hợp, thiếu tổng quát, quá phụ thuộc vào kỹ thuật cài đặt phần mềm và quá tốn công sức thu thập. Trong nghiên cứu này, nhóm tác giả phát triển 6 độ đo dành cho các thiết kế hướng đối tượng (HĐT) nhằm khắc phục các hạn chế của các độ đo phần mềm trước đó.
Theo các tác giả, quá trình thiết kế hướng đối tượng có bốn bước cơ bản: xác định các lớp, xác định ngữ nghĩa của các lớp, xác định mối quan hệ giữa các lớp và thiết kế các hàm thực thi liên quan đến các lớp đó. Trong hệ thống HĐT, mô hình lớp đóng vai trò quan trọng nhất. Các tác giả đề xuất độ đo độ cho mô hình lớp.
Các tác giả đã lập luận cơ sở lý thuyết của các độ đo, xây dựng các tiêu chí đánh giá các độ đo. Các độ đo được thử nghiệm trên các ứng dụng lớn, được phát triển bởi các ngôn ngữ lập trình khác nhau. Kết quả thu được cho
36
thấy rất có ý nghĩa đối với các hoạt động phát triển, như kiểm thử, gỡ rối và bảo trì [23].
Phương pháp của Paynevà các đồng tác giả
Payne và các đồng tác giả [24] đề xuất phương pháp thiết kế sử dụng các hợp đồng phần mềm (software contract) trong đặc tả và chèn các xác nhận (assertion) vào mã nguồn khi cài đặt để nâng cao khả năng quan sát (observability ) và khả năng điều khiển (controllability), nghĩa là nâng cao tính khả kiểm thử.
Hợp đồng phần mềm là sự đặc tả hình thức ngữ nghĩa hành vi của lớp và các phương thức của lớp. Hợp đồng phần mềm gồm ba thành phần chính:
− biểu thức bất biến (invariant) định nghĩa tính nhất quán đối với không gian trạng thái của lớp;
− tiền điều kiện (precondition) cho mỗi phương thức, định nghĩa các điều kiện để gọi phương thức đó;
− hậu điều kiện (postcondition) cho mỗi phương thức, định nghĩa chính xác phương thức làm gì.
Nhóm tác giả cho rằng tiền điều kiện và hậu điều kiện là cơ chế giúp nâng cao tính khả kiểm thử của lớp. Tiền điều kiện của phương thức cho phép điều khiển và quan sát dữ liệu đầu vào. Hậu điều kiện cho phép quan sát kết quả đầu ra. Hợp đồng phần mềm được sử dụng để đặc tả lớp, trong bước cài đặt, các thành phần của hợp đồng phần mềm (bất biến, tiền điều kiện và hậu điều kiện) được chèn vào trong mã nguồn tại các vị trí quan trọng bằng cách sử dụng các xác nhận.
Việc chèn các xác nhận trong mã nguồn giúp cải tiến tính khả kiểm thử, bởi vì: có thể lấy được thông tin về sự nhất quán, hợp lệ của trạng thái đối
37
tượng; việc sử dụng phương thức không đúng được xác định sớm; và lỗi cài đặt được xác định nhanh chóng.
Theo các tác giả, việc chèn các xác nhận về bất biến, tiền điều kiện và hậu điều kiện làm tăng tính khả kiểm thử, tuy nhiên có thể không phát hiện được lỗi trạng thái dữ liệu (nếu có) khi phương thức được thực thi. Bởi vì, có những lỗi trạng thái dữ liệu không thểđược phát hiện bởi các xác nhận về bất biến, tiền điều kiện và hậu điều kiện. Do đó, các tác giả đã đề xuất sử dụng thêm xác nhận dữ liệu (data assertion) vào các vị trí quan trọng trong phương thức nhằm cải tiến khả năng quan sát.
Đối với quan hệ thừa kế giữa các lớp, nghiên cứu này chỉ xem xét quan hệ giữa lớp con và lớp cha. Gọi lớp B là lớp con của lớp A, khi đó hành vi của
B phải bao gồm hành vi của lớp A. Nếu phương thức mA của lớp A bị thay thế bởi mB ở lớp B, khi đó các xác nhận được đưa vào để kiểm tra điều kiện:
Tiền điều kiện(mA) ⇒Tiền điều kiện(mB) và Hậu điều kiện(mB) ⇒Hậu điều kiện(mA) Ngoài ra, trong nghiên cứu này, hợp đồng phần mềm và xác nhận còn được sử dụng để điều khiển quan hệ thừa kế và thứ tự gọi các phương thức. Để thực hiện việc này, nhóm tác giả đề xuất kỹ thuật down-calling. Trong đó, các phương thức được làm hai loại: phương thức giao diện (interface method) và phương thức cài đặt (implementation method). Phương thức giao diện
(không phải là phương thức trong giao diện theo nghĩa của lập trình hướng đối tượng) được khai báo public trong lớp cơ sở (lớp cha), trong các lớp dẫn xuất (lớp con) không cho phép cài đặt nội dung thực thi đè lên phương thức này. Trong phương thức này chứa các xác nhận để kiểm tra bất biến, tiền điều kiện và hậu điều kiện và lời gọi đến phương thức thực thi. Phương thức cài
38
hướng đối tượng) không được khai báo public lớp cơ sở (lớp cha), trong các lớp dẫn xuất (lớp con) phương thức này được cài đặt nội dung thực thi.
Kỹ thuật down-calling bảo đảm rằng: khi thực thi trong các lớp dẫn xuất, các phương thức giao diện được gọi, như thế các xác nhận kiểm tra bất biến, tiền điều kiện và hậu điều kiện được thực hiện nhằm đảm bảo về mặt ngữ nghĩa của phương thức; sau đó, phương thức cài đặt được gọi để thực thi chức năng được cài đặt. Hơn nữa, để đảm bảo các phương thức phải thực thi theo đúng thứ tự xác định, nghiên cứu này đề xuất sử dụng các ràng buộc thứ tự
(sequencing constraints). Các ràng buộc này là sự mở rộng của tiền điều kiện. Thứ tự gọi các phương thức được mô hình hóa bởi một sơ đồ trạng thái, trong đó các sự kiện kích hoạt các chuyển tiếp là các lời gọi phương thức. Các xác nhận tiền điều kiện được bổ sung để đảm bảo các ràng buộc thứ tự gọi các phương thức.
Nghiên cứu này cho thấy việc sử dụng các xác nhận và hợp đồng phần mềm trong thiết kế và cài đặt các phần mềm hướng đối tượng đóng vai trò quan trọng trong việc nâng cao tính khả kiểm thử [24].
Phương pháp của Jungmayr
Jungmayr [13, 14] xây dựng các độ đo về tính khả kiểm thử dựa trên sự phụ thuộc của các thành phần (component) phần mềm hướng đối tượng. Phần mềm được mô tả bởi đồ thị phụ thuộc (dependency graph), gồm tập hợp các thành phần và sự phụ thuộc giữa chúng. Tác giả định nghĩa một số khái niệm về sự phụ thuộc:
− Một thành phần phụ thuộc thành phần khác được gọi là một thành phần phụ thuộc (dependent component).
− Một thành phần cần cho các thành phần khác được gọi là thành phần cơ sở (dependee component).
39
− Đồ thị phụ thuộc chứa chu trình được gọi là chu trình phụ thuộc
(dependency cycles).
− Tập hợp các phụ thuộc mà nếu loại bỏ chúng sẽ làm cho đồ thị phụ thuộc không chứa chu trình được gọi là tập phụ thuộc phản hồi
(feedback dependency set). Mỗi phụ thuộc trong tập phụ thuộc phản hồi được gọi là một phụ thuộc phản hồi (feedback dependency).
− Tập hợp các thành phần mà sự loại bỏ chúng làm cho đồ thị phụ thuộc không chứa chu trình gọi là tập thành phần phản hồi
(feedback component set).
Jungmayr cho rằng sự phụ thuộc giữa các thành phần phần mềm có ảnh hưởng lớn đến thời gian, chi phí và độ phức tạp của kiểm thử:
− Các thành phần cơ sở phải được xem xét khi kiểm thử.
− Tăng thời gian biên dịch lại phần mềm, khi các thành phần thay đổi.
− Các thành phần cơ sở phải được khởi tạo trong quá trình thiết lập việc kiểm thử.
− Kiểm thử tích hợp trở nên khó hơn. − Xác định lỗi trở nên khó hơn.
Ngoài ra, chu trình phụ thuộc còn gây thêm các vấn đề về kiểm thử: − Những thành phần trong chu trình phải được kiểm thử cùng một
lúc.
− Nhiều nút trám (stubs) phải được cài đặt thêm, nếu cần bẻ gãy chu trình.
− Có thể xuất hiện tình huống mà một phương thức được gọi, trong khi phương thức đó đang thực thi, gây khó hiểu và làm cho việc xác định lỗi khó hơn.
40
Trước hết, Jungmayr xác định các mục tiêu của việc cải tiến tính khả kiểm thử. Sau đó, các độ đo tính khả kiểm thử được định nghĩa nhằm đo lường mức độđạt được các mục tiêu đặt ra.
Hai mục tiêu cải tiến tính khả kiểm thử gồm:
- Mục tiêu 1: kiểm thử một cách độc lập nhất có thể các thành phần – khi kiểm thử một thành phần, hạn chế tối thiểu việc xem xét các thành phần cơ sở liên quan.
- Mục tiêu 2: hạn chế chi phí kiểm thử hồi quy – khi một thành phần thay đổi, hạn chế tối thiểu việc kiểm thử lại các thành phần khác.
Từ đó, tác giả đã định nghĩa một sốđộ đo tính khả kiểm thử. Các độ đo tính khả kiểm thử trên đã được tích hợp vào công cụ ImproveT [14] và đã được thử nghiệm trên nhiều dự án phần mềm khác nhau. Kết quả cho thấy sự phụ thuộc giữa các thành phần có ảnh hưởng lớn đến tính khả kiểm thử phần mềm [14].
Phương pháp của Baudry và các đồng tác giả
Baudry và các đồng tác giả [25, 26] cho rằng tính khả kiểm thử là sự dễ dàng kiểm thử phần mềm. Tính khả kiểm thửđược đánh giá bởi ba yếu tố:
− Chi phí kiểm thử: gồm chi phí để tạo bộ dữ liệu thử đạt tiêu chí đặt ra và chi phí xác định sự hợp lệ của kết quả kiểm thử.
− Khả năng điều khiển: sự dễ dàng tạo ra dữ liệu thử.
− Khả năng quan sát: sự dễ dàng kiểm tra sự hợp lệ của kết quả kiểm thử.
Các tác giả cho rằng có hai yếu tố làm giảm tính khả kiểm thử là sự tương tác giữa các lớp (class interactions) và việc một lớp sử dụng chính nó (self-usage). Những hạn chế này làm tăng chi phí kiểm thử. Bởi vì, cả hai hạn chế này trong thiết kế sơ đồ lớp đòi hỏi các dữ liệu thử được tạo ra phải bao
41
phủ các đường đi (path) qua nhiều lớp, như thế, việc tạo ra dữ liệu sẽ rất khó khăn.
Nhằm xác định các hạn chế về tương tác trong sơ đồ lớp, các tác giả đề xuất xây dựng đồ thị phụ thuộc lớp (class dependency graph). Đồ thị này biểu diễn các lớp và quan hệ giữa các lớp, gồm quan hệ sử dụng và quan hệ thừa kế. Sau đó, các hạn chế tương tác giữa các lớp và một lớp sử dụng chính nó được xác định dựa trên việc xác định các đường đi và chu trình trong đồ thị.
Các tác giả cũng đã định nghĩa các độ đo độ phức tạp của tương tác giữa các lớp. Dựa trên cơ sở đó, một số cải tiến tính khả kiểm thử được đề xuất nhằm đạt được thiết kế có chất lượng hơn [25, 26].
Phương pháp của Kansomkeat và các đồng tác giả
Kansomkeat và các đồng tác giả [27, 28] đã nghiên cứu phương pháp phân tích tính khả kiểm thử của lớp dựa trên việc phân tích luồng dữ liệu (data-flow analysis) bằng kỹ thuật phân tích đột biến (mutation analysis).
Phân tích luồng dữ liệu nhằm đảm bảo các giá trị đúng đắn của các biến chương trình lưu trong bộ nhớ và được sử dụng sau đó. Khi biến được định nghĩa được gọi là def. Khi biến được sử dụng gọi là use. Một cặp du-pair của một biến là một đường đi từ một def đến một use, mà trên đường đi đó không có sự định nghĩa (gán) lại biến đó.
Phân tích đột biến thường được sử dụng để đánh giá chất lượng của bộ dữ liệu thử. Kỹ thuật đột biến chèn một lỗi vào chương trình cần được kiểm thử, hay còn gọi là chương trình gốc, để tạo ra đột biến (mutant). Nếu đột biến và chương trình gốc cho kết quả khác nhau khi thực thi với cùng một dữ liệu thử, thì đột biến được gọi là bị diệt (killed). Các đột biến được tạo ra bởi việc áp dụng các toán tử đột biến (mutation operators). Mỗi toán tửđột biến là một sự thay đổi đơn giản trong chương trình gốc. Ví dụ, thay đổi một toán tử số
42
học hay một toán tử lô-gíc. Kết quả của phân tích đột biến được xác định bởi
tỷ lệ đột biến (mutation score), là tỷ lệ số đột biến bị diệt bởi một bộ dữ liệu thử. Tỷ lệ này càng lớn thì bộ dữ liệu thử được xem càng có chất lượng.
Trong nghiên cứu này, các tác giả cho rằng tính khả kiểm thử là xác suất các lỗi tồn tại sẽ được phát hiện khi kiểm thử. Kỹ thuật phân tích luồng dữ liệu có thể được sử dụng để phát hiện lỗi. Các khái niệm def và use được sử dụng để phân tích tính khả kiểm thử.
Để đánh giá tính khả kiểm thử của một vị trí (tức là một câu lệnh), vị trí chứa lỗi đó phải được thực thi. Nếu việc thực thi đó mang lại kết quả sai lệch, thì tính khả kiểm thử được xem là cao. Nếu xác suất vị trí l được thực thi là
E(l), được gọi là xác suất thực thi, xác suất để trạng thái dữ liệu sai đó ảnh hưởng đến đầu ra là P(l), được gọi là xác suất lan truyền, khi đó tính khả kiểm thử tại vị trí l, T(l), được định nghĩa như sau:
T(l) = E(l) * P(l)
Như vậy, việc đánh giá tính khả kiểm thử chính là đánh giá xác suất thực thi và xác suất lan truyền tại mỗi vị trí trong lớp. Tính khả kiểm thử tại mỗi vị trí l, T(l), được tính bằng tích của xác suất thực thi và xác suất lan truyền. Tính khả kiểm thửT của lớp là giá trị trung bình của tính khả kiểm thử của tất cả các vị trí def và use. Nếu lớp có k vị trí def và use thì:
T = (∑ T(i) [i =1, 2, …, k]) / k.
Kỹ thuật phân tích tính khả kiểm thử này áp dụng cho mã nguồn của một lớp. Ngoài ra, nhóm tác giả còn đề xuất áp dụng cho mức mã biên dịch dạng bytecode (đối với ngôn ngữ Java), một khi không có mã nguồn. Mã bytecode sẽ được chỉnh sửa trực tiếp, bởi công cụ BCEL (Byte Code Engineering Library) của Apache/Jakarta, để đánh giá xác suất thực thi và xác suất lan truyền. Kỹ thuật phân tích tính khả kiểm thử dựa trên đánh giá xác suất thực
43
thi và xác suất lan truyền áp dụng cho mức mã thực thi của lớp. Kỹ thuật này rất có ý nghĩa khi không có sẵn mã nguồn để phân tích. Ngoài ra, nhóm tác giả còn cho rằng phân tích mã thực thi sẽ cho kết quả chính xác hơn so với việc phân tích sơđồ lớp [27, 28].