Bảng 7.8. Các qui tắc trong bảng quyết định
Ví dụ: Để tính thuế thu nhập, người ta có mô tả sau:
- Người vô gia cư nộp 4% thuế thu nhập
- Người có nhà ở nộp thuế theo quy tắc nếu tổng thu nhập <= 5.000.000 đồng thì nộp 4% thuế thu nhập, ngược lại nộp 6%.
Hãy xây dựng các trường hợp kiểm thử bằng phương pháp sơ đồ nguyên nhân - kết quả.
- Liệt kê và gán tên cho các nguyên nhân và kết quả
Bảng 7.9. Các nguyên nhân và kết quả của bài toán tính thuế
Có thể bạn quan tâm!
- Mức Độ Áp Dụng Mẫu Trong Quá Trình Phát Triển Phần Mềm
- Xây Dựng Các Tình Huống Kiểm Thử (Test Case)
- Bảng Liệt Kê Các Lớp Tương Đương Của Chương Trình Nhập Điểm
- Vai Trò Và Công Việc Của Cán Bộ Kiểm Thử (Tester)
- Công nghệ phần mềm - Phạm Hùng Phú, Nguyễn Văn Thẩm Biên soạn - 32
- So Sánh Chi Phí Cho Các Giai Đoạn Phát Triển Phần Mềm
Xem toàn bộ 305 trang tài liệu này.
- Xây dựng đồ thị nguyên nhân - kết quả
- Chuyển đồ thị thành bảng quyết định
Bảng 7.10. Bảng quyết định của bài toán tính thuế
7.4.2. Kiểm thử White-box
1) Ý tưởng
Phần mềm là một hệ thống gồm 3 thành phần cơ bản: thành phần lưu trữ, thành phần giao tiếp, thành phần xử lý cần phải thực hiện theo yêu cầu của người dùng
Thành phần giao tiếp: Giao diện chương trình
Thành phần lưu trữ: Cho phép lưu trữ và truy xuất dữ liệu
Thành phần xử lý: Thực hiện các xử lý theo qui trình nghiệp vụ của người dùng
Hình 7.5. Kiểm thử White-box
Ý tưởng của phương pháp kiểm thử White-box (hộp trắng):
- Quan tâm đến các xử lý tức giải thuật, thuật toán
- Sử dụng và có tính đến các thông tin về cấu trúc chương trình
- Thử nghiệm chức năng mà chương trình cung cấp
- Thường tốn rất nhiều thời gian và công sức nếu mức độ kiểm thử được nâng lên ở cấp kiểm thử tích hợp hay kiểm thử hệ thống.
- Được dùng để kiểm thử đơn vị. Trong lập trình hướng đối tượng, kiểm thử đơn vị là kiểm thử từng tác vụ của một class chức năng nào đó.
Do đó, người kiểm thử (Tester):
- Kiểm thử tính logic và cấu trúc của mã nguồn (source code): bao gồm server code và client.
- Có kiến thức về
+ Ngôn ngữ lập trình (C, C++, VB.NET, Java,…)
+ Môi trường phát triển phần mềm (IDE)
+ Các hệ quản trị cơ sở dữ liệu (SQL Server, Oracle, DB2,…)
- Kiểm thử tất cả các trường hợp có thể xảy ra trong mã nguồn (cấu trúc điều khiển, cấu trúc lặp,…)
2) Các phương pháp kiểm thử White-box
a. Kiểm thử dựa trên đồ thị luồng điều khiển (Control Flow Graph-CFG)
Kiểm thử dựa trên đồ thị luồng điều khiển là một kỹ thuật kiểm thử hộp trắng do Tom McCabe đề xuất. Phương pháp này cho phép người thiết kế trường hợp kiểm thử thực hiện phép đo độ phức tạp logic của thiết kế thủ tục và sử dụng phép đo này như một chỉ dẫn cho việc thiết kế một tập cơ sở các đường dẫn thực hiện.
Những trường hợp kiểm thử được suy diễn để thực hiện tập cơ sở. Các trường hợp kiểm thử đó được đảm bảo để thực hiện mỗi lệnh trong chương trình ít nhất một lần trong quá trình kiểm thử.
Mục tiêu của phương pháp kiểm thử luồng điều khiển là đảm bảo mọi đường thi hành của đơn vị phần mềm cần kiểm thử đều chạy đúng. Rất tiếc trong thực tế, công sức và thời gian để đạt mục tiêu trên đây là rất lớn, ngay cả trên những đơn vị phần mềm nhỏ.
Các bước:
Bước 1: Xây dựng đồ thị dòng điều khiển tương ứng từ thủ tục cần kiểm thử Bước 2: Tính độ phức tạp Cyclomatic của đồ thị (=C).
Bước 3: Xác định C đường thi hành tuyến tính cơ bản cần kiểm thử. Bước 4: Tạo từng test case cho từng đường thi hành tuyến tính cơ bản. Bước 5: Thực hiện kiểm thử trên tứng test case.
Bước 6: So sánh kết quả có được với kết quả được kỳ vọng.
Bước 7: Lập báo cáo kết quả để phản hồi cho những người có liên quan.
Xây dựng đồ thị dòng điều khiển tương ứng
- Các thành phần cơ bản:
- Các cấu trúc điều khiển phổ dụng:
Tính độ phức tạp Cyclomatic của đồ thị (=C)
Độ phức tạp Cyclomatic C = V(G) của đồ thị dòng điều khiển được tính bởi 1 trong các công thức sau :
- V(G) = E - N + 2, trong đó E là số cung, N là số nút của đồ thị.
- V(G) = P + 1, nếu đồ thị chỉ chứa các nút quyết định luận lý (chỉ có 2 cung xuất True/False) và P số nút quyết định.
Xác định C đường thi hành tuyến tính cơ bản cần kiểm thử.
- Độ phức tạp Cyclomatic C chính là số đường thi hành tuyến tính độc lập cơ bản của thủ tục cần kiểm thử.
- Nếu chúng ta chọn lựa được đúng C đường thi hành tuyến tính độc lập cơ bản của thủ tục cần kiểm thử và kiểm thử tất cả các đường thi hành này.
- Đường thi hành (Execution path): Là một kịch bản thi hành đơn vị phần mềm tương ứng: danh sách có thứ tự các lệnh được thi hành ứng với một lần chạy cụ thể của đơn vị phần mềm, bắt đầu từ điểm nhập của đơn vị phần mềm đến điểm kết thúc của đơn vị phần mềm.
Qui trình xác định các đường tuyến tính độc lập
Bước 1: Xác định đường cơ bản, đường này nên là đường thi hành phố biến
nhất.
Bước 2: Để chọn đường thứ 2, thay đổi cung xuất của nút quyết định đầu tiên
và cố gắng giữ lại maximum phần còn lại.
Bước 3: Để chọn đường thứ 3, dùng đường cơ bản nhưng thay đổi cung xuất của nút quyết định thứ 2 và cố gắng giữ lại maximum phần còn lại.
Bước 4: Tiếp tục thay đổi cung xuất cho từng nút quyết định trên đường cơ bản để xác định đường thứ 4, 5,... cho đến khi không còn nút quyết định nào trong đường cơ bản nữa.
Bước 5: Lặp dùng tuần tự các đường tìm được làm đường cơ bản để xác định các đường mới xung quanh nó y như các bước 2, 3, 4 cho đến khi không tìm được đường tuyến tính độc lập nào nữa (khi đủ số C).
Ví dụ: Xét thủ tục sau
double average(double value[], double min, double max, int& tcnt, int&
vcnt)
{
double sum = 0; int i = 1;tcnt = vcnt = 0; while (value[i] <> -999 && tcnt <100)
{
i++;
}
tcnt++;
if (min<=value[i] && value[i] <= max)
{sum += value[i]; vcnt ++;}
if (vcnt > 0) return sum/vcnt; return -999;}
Hãy xây dựng các trường hợp kiểm thử dựa trên đồ thị luồng điều khiển
Xây dựng đồ thị dòng điều khiển tương ứng từ thủ tục cần kiểm thử
Tính độ phức tạp Cyclomatic của đồ thị
- Cách 1: C= E - N + 2=18-14+2=6
- Cách 2: C = P+1=5+1 = 6
Xác định C đường thi hành tuyến tính cơ bản cần kiểm thử. 1. 121011
2. 1231011
3. 121012
4. 1234589
5. 12345689
6. 123456789
Tạo từng test case cho từng đường thi hành tuyến tính cơ bản.
- Test case cho đường 1 : value(k) <>-999, với 1< k < i value(i) = -999 với 2 ≤ i ≤ 100
Kết quả kỳ vọng : (1) average=Giá trị trung bình của k giá trị hợp lệ. (2) tcnt =
k. (3) vcnt = k
Chú ý : không thể kiểm thử đường 1 này riêng biệt mà phải khiểm thử chung với đường 4 hay 5 hay 6.
- Test case cho đường 2 :
value(k) <>-999, với k < i , i >100
Kết quả kỳ vọng : (1) average=Giá trị trung bình của 100 giá trị hợp lệ. (2) tcnt
= 100. (3) vcnt = 100
- Test case cho đường 3 : value(1) = -999
Kết quả kỳ vọng : (1) average = -999. (2) tcnt = 0 (3) vcnt = 0
- Test case cho đường 4 :
value(i) <> -999 i <= 100 và value(k) < min với k < i
Kết quả kỳ vọng : (1) average=Giá trị trung bình của n giá trị hợp lệ. (2) tcnt =
100. (3) vcnt = n (số lượng giá trị hợp lệ)
- Test case cho đường 5 : value(i) <>-999 với i <= 100 và value(k) > max với k <= i
Kết quả kỳ vọng : (1) average=Giá trị trung bình của n giá trị hợp lệ. (2) tcnt =
100. (3) vcnt = n (số lượng giá trị hợp lệ)
- Test case cho đường 6 :
value(i) <>-999 và min <= value(i) <= max với i <= 100
Kết quả kỳ vọng : (1) average=Giá trị trung bình của 100 giá trị hợp lệ. (2) tcnt
= 100. (3) vcnt = 100
b. Kiểm thử cấu trúc điều khiển
Kiểm thử điều kiện
Kiểm thử điều kiện là phương pháp thiết kế trường hợp kiểm thử thực thi các điều kiện logic trong module chương trình.
Một số định nghĩa:
- Điều kiện đơn: là một biến logic hoặc một biểu thức quan hệ, có thể có toán tử NOT (!) đứng trước, ví dụ, NOT (a>b)
- Biểu thức quan hệ: là một biểu thức có dạng E1
- Điều kiện phức: gồm hai hay nhiều điều kiện đơn, toán tử logic AND (&&) hoặc OR (||) hoặc NOT (!) và các dấu ngoặc đơn “(„ và „)‟, ví dụ, (a > b + 1) AND (a
<= max).
Vì vậy, các thành phần trong một điều kiện có thể gồm phép toán logic, biến logic, cặp dấu ngoặc logic (bao một điều kiện đơn hoặc phức), phép toán quan hệ, hoặc biểu thức toán học
Mục đích của kiểm thử điều kiện là để xác định không chỉ các lỗi điều kiện mà cả các lỗi khác trong chương trình. Có một số phương pháp kiểm thử điều kiện được đề xuất:
- Kiểm thử nhánh (Branch Testing): là phương pháp kiểm thử điều kiện đơn giản nhất.
- Kiểm thử miền (Domain Testing): Cần 3 hoặc 4 kiểm thử cho biểu thức quan hệ. Với một biểu thức quan hệ có dạng E1
- Kiểm thử nhánh và toán tử quan hệ (Branch and Relational Operator - BRO).
Kiểm thử luồng dữ liệu
Phương pháp kiểm thử luồng dữ liệu lựa chọn các đường dẫn kiểm thử của chương trình dựa vào vị trí khai báo và sử dụng các biến trong chương trình. Với kiểm thử luồng dữ liệu mỗi câu lệnh trong chương trình được gán số hiệu lệnh duy nhất và mỗi hàm không thay đổi tham số của nó và biến toàn cục. Cho một lệnh với S là số hiệu câu lệnh. Ta định nghĩa,
DEF(S) = là tập các biến được khai báo trong S. USE(S) = là tập các biến được sử dụng trong S.
Một chiến lược kiểm thử luồng dữ liệu cơ bản là chiến lược mà mỗi chuỗi DU được phủ ít nhất một lần. Chiến lược này được gọi là chiến lược kiểm thử DU. Kiểm thử DU không đảm bảo phủ hết tất cả các nhánh của một chương trình. Tuy nhiên, một nhánh không đảm bảo được phủ bởi kiểm thử DU chỉ trong rất ít tình huống như cấu trúc if-then-else mà trong đó phần then không có một khai báo biến nào và có dạng khuyết (không tồn tại phần else). Trong tình huống đó, nhánh else của lệnh if là không
cần thiết phải phủ bằng kiểm thử DU. Chiến lược kiểm thử luồng dữ liệu là rất hữu ích cho việc lựa chọn các đường dẫn kiểm thử của chương trình có chứa các lệnh if hoặc vòng lặp lồng nhau.
Kiểm thử vòng lặp
Kiểm thử vòng lặp là một kỹ thuật kiểm thử hộp trắng mà tập trung trên tính hợp lệ của các cấu trúc lặp.
Việc xây dựng các trường hợp kiểm thử cho mỗi loại cần thực hiện như sau:
- Vòng lặp đơn: Với vòng lặp đơn trong đó N là số lần lặp tối đa, các trường hợp kiểm thử sau được sử dụng để kiểm thử mỗi điều kiện sau: Bỏ qua vòng lặp, chỉ một lần lặp, hai lần lặp, M lần lặp trong đó M < N; N-1, N, N+1 lần lặp.
- Vòng lặp lồng nhau
+ Bắt đầu tại vòng lặp trong cùng,
+ Xây dựng các kiểm thử vòng lặp đơn cho vòng lặp trong cùng, trong khi đó giữ vòng lặp ngoài cùng tại các giá trị tham số lặp nhỏ nhất của chúng.
+ Phát triển ra phía ngoài, xây dựng các kiểm thử cho vòng lặp tiếp theo, nhưng giữ tất cả các vòng lặp bên ngoài với giá trị nhỏ nhất và các vòng lặp lồng nhau khác giá trị “đặc biệt”. Tiếp tục cho đến khi tất cả các vòng lặp được kiểm thử.
- Vòng lặp nối nhau: Nếu các vòng lặp nối nhau là độc lập thì chúng có thể được xem như hai vòng lặp đơn riêng biệt, sử dụng phương pháp kiểm thử vòng lặp đơn. Nếu vòng lặp thứ hai phụ thuộc vào vòng lặp trước (ví dụ, biến đếm của vòng lặp 1 là giá trị khởi tạo của vòng lặp 2), thì xem chúng như các vòng lặp lồng nhau và sử dụng cách tiếp cận kiểm thử vòng lặp lồng nhau.
- Vòng lặp phi cấu trúc: Nếu gặp các lớp vòng lặp này chúng ta sẽ không kiểm thử mà sẽ thiết kế lại tương ứng với sử dụng việc xây dựng chương trình có cấu trúc.
c. Kiểm thử đột biến (mutation testing)
Kiểm thử đột biến được đề xuất đầu tiên năm 1978 bởi DeMillo, 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: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.