Chương 1, trong chương này tác giả luận văn sẽ tập trung vào nghiên cứu và trình bày các phương pháp kiểm thử dòng dữ liệu tĩnh. Phƣơng pháp kiểm thử dòng dữ liệu tĩnh Chúng ta đã biết, kiểm thử dòng điều khiển và kiểm thử dòng dữ liệu được xem là hai phương pháp chủ yếu trong chiến lược kiểm thử hộp trắng nhằm phát hiện các lỗi tiềm tàng bên trong các chương trình/đơn vị chương trình. Phương pháp kiểm thử dòng điều khiển cho phép sinh ra các ca kiểm thử (tương ứng với các đường đi dòng điều khiển) của chương trình. Tuy nhiên, chỉ áp dụng phương pháp này là chưa đủ để phát hiện tất cả các lỗi tiềm ẩn bên trong chương trình.
Trong thực tế, các lỗi thường hay xuất hiện tại các biến được sử dụng trong chương trình/đơn vị chương trình. Kiểm thử dòng dữ liệu cho phép chúng ta phát hiện những lỗi này. Bằng cách áp dụng cả hai phương pháp này, chúng ta khá tự tin về chất lượng của sản phẩm phần mềm [1]. Với phạm vi nghiên cứu của đề tài, trong chương này sẽ trình bày phương pháp kiểm thử dòng dữ liệu tĩnh.
Ý tƣởng của phƣơng pháp Mỗi chương trình/đơn vị chương trình là chuỗi các hoạt động gồm nhận các giá trị đầu vào, thực hiện các tính toán, gán giá trị mới cho các biến (các biến cục bộ và toàn cục) và cuối cùng là trả lại kết quả đầu ra như mong muốn. Khi một biến được khai báo và gán giá trị, nó phải được sử dụng ở đâu đó trong chương trình. Ví dụ, khi khai báo một biến int tem = 0, chúng ta hy vọng biến tem sẽ được sử dụng ở các câu lệnh tiếp theo trong đơn vị chương trình. Việc sử dụng biến này có thể trong các câu lệnh tính toán hoặc trong các biểu thức điều kiện.
Nếu biến này không được sử dụng ở các câu lệnh tiếp theo thì việc khai báo biến này là không cần thiết. Hơn nữa, cho dù biến này có được sử dụng thì tính đúng đắn của chương trình chưa chắc đã đảm bảo vì lỗi có thể xảy ra trong quá trình tính toán hoặc trong các biểu thức điều kiện. Để giải quyết vấn đề này, phương pháp kiểm thử dòng dữ liệu xem đơn vị chương trình gồm các đường đi tương ứng với các dòng dữ liệu nơi mà các biến được khai báo, được gán giá trị, được sử dụng để tính toán và trả lại kết quả mong muốn của đơn vị chương trình ứng với đường đi này. LUAN VAN CHAT LUONG download : add luanvanchat@agmail.com 19 Với mỗi đường đi, chúng ta sẽ sinh một ca kiểm thử để kiểm tra tính đúng đắn của nó.
Quá trình kiểm thử dòng dữ liệu được chia thành hai pha riêng biệt: kiểm thử dòng dữ liệu tĩnh (static data flow testing) và kiểm thử dòng dữ liệu động (dynamic data flow testing). Với kiểm thử dòng dữ liệu tĩnh, chúng ta áp dụng các phương pháp phân tích mã nguồn mà không cần chạy chương trình/đơn vị chương trình nhằm phát hiện các vấn đề về khai báo, khởi tạo giá trị cho các biến và sử dụng chúng. Chi tiết về vấn đề này sẽ được trình bày trong phần tiếp theo. Với kiểm thử dòng dữ liệu động, chúng ta sẽ chạy các ca kiểm thử nhằm phát hiện các lỗi tiềm ẩn mà kiểm thử tĩnh không phát hiện được.
Các vấn đề bất thƣờng trong dòng dữ liệu Trong quá trình lập trình, các lập trình viên có thể viết các câu lệnh “bất thường” hoặc không tuân theo chuẩn lập trình. Chúng ta gọi những bất thường liên quan đến việc khai báo, khởi tạo giá trị cho các biến và sử dụng chúng là các vấn đề về dòng dữ liệu của đơn vị chương trình. Ví dụ, một lập trình viên có thể sử dụng một biến mà không khởi tạo giá trị sau khi khai báo nó (int x; if (x==100) {…}). Các vấn đề bất thường về dòng dữ liệu có thể được phát hiện bằng phương pháp kiểm thử dòng dữ liệu tĩnh.
Theo Fosdick và Osterweil [4], các vấn đề này được chia thành ba loại như sau: Gán giá trị rồi gán tiếp giá trị (Loại 1) [4]: Ví dụ hình dưới đây chứa hai câu lệnh tuần tự x = f1(y); x = f2(z); với f1 và f2 là các hàm đã định nghĩa trước và y, z lần lượt là các tham số đầu vào của các hàm này.1: Tuần tự các câu lệnh có vấn đề thuộc loại 1 Chúng ta có thể xem xét hai câu lệnh tuần tự này với các tình huống sau: - Khi câu lệnh thứ hai được thực hiện, giá trị của biến x được gán và câu lệnh đầu không có ý nghĩa; - Lập trình viên có thể có nhầm lẫn ở câu lệnh đầu. Câu lệnh này có thể là gán giá trị cho một biến khác như là w = f1(y); LUAN VAN CHAT LUONG download : add luanvanchat@agmail.com 20 - Có thể có nhầm lẫn ở câu lệnh thứ hai. Lập trình viên định gán giá trị cho một biến khác như là w = f2(z). - Một hoặc một số câu lệnh giữa hai câu lệnh này bị thiếu.
Ví dụ như câu lệnh w = f3(x). Chỉ có lập trình viên và một số thành viên khác trong dự án mới có thể trả lời một cách chính xác vấn đề trên thuộc trường hợp nào trong bốn tình huống trên. Mặc dù vậy, những vấn đề tương tự như ví dụ này là khá phổ biến và chúng ta cần phân tích mã nguồn để phát hiện ra chúng. Chưa gán giá trị nhưng được sử dụng (Loại 2) [4]: Ví dụ hình dưới đây chứa ba câu lệnh tuần tự với y là một biến đã được khai báo và gán giá trị (y = f(x1)).
Trong trường hợp này, biến z chưa được gán giá trị khởi tạo nhưng đã được sử dụng trong câu lệnh để tính giá trị của biến x (x=y+z).2: Tuần tự các câu lệnh có vấn đề thuộc loại 2 Chúng ta cũng có thể lý giải vấn đề này theo các tình huống sau: - Lập trình viên có thể bỏ quên lệnh gán giá trị cho biến z trước câu lệnh tính toán giá trị cho biến x. Ví dụ, z = f2(x2), với f2 là một hàm đã được xác định và x2 là một biến đã được khai báo và gán giá trị. - Có thể có sự nhầm lẫn giữa biến z với một biến đã được khai báo và gán giá trị. Đã được khai báo và gán giá trị nhưng không được sử dụng (Loại 3) [4]: Nếu một biến đã được khai báo và gán giá trị nhưng không hề được sử dụng (trong các câu lệnh tính toán hoặc trong các biểu thức điều kiện), chúng ta cần xem xét cẩn thận vấn đề này.
Tương tự như các trường hợp trên, các tình huống sau có thể được sử dụng để lý giải cho vấn đề này: - Có sự nhầm lẫn giữa biến này và một số biến khác được sử dụng trong chương trình. Trong thiết kế, biến này được sử dụng nhưng nó đã bị thay thế (do nhầm lẫn) bởi một biến khác. - Biến này thực sự không được sử dụng trong chương trình. Lúc đầu lập trình viên định sử dụng nó như là một biến tạm thời hoặc biến trung gian nhưng LUAN VAN CHAT LUONG download : add luanvanchat@agmail.com 21 sau đó lại không cần dùng.
Lập trình viên này đã quên xóa các câu lệnh khai báo và gán giá trị cho biến này. Huang [5] đã giới thiệu một phương pháp để xác định những bất thường trong việc sử dụng các biến dữ liệu bằng cách sử dụng sơ đồ chuyển trạng thái ứng với mỗi biến dữ liệu của chương trình. Các thành phần của sơ đồ chuyển trạng thái của một chương trình ứng với mỗi biến gồm: • Các trạng thái, gồm: - U: biến chưa được gán giá trị - D: biến đã được gán giá trị nhưng chưa được sử dụng - R: biến đã được sử dụng - A: trạng thái lỗi • Các hành động, gồm: - d: biến được gán giá trị - r: biến được sử dụng - u: biến chưa được gán giá trị hoặc được khai báo lại và chưa được gán giá trị.3: Sơ đồ chuyển trạng thái của một biến Hình 2.3 mô tả sơ đồ chuyển trạng thái của một biến trong một chương trình/đơn vị chương trình. Ban đầu, biến này đã được khai báo và chưa được gán giá trị nên trạng thái của chương trình là U.
Tại trạng thái này, nếu biến này được sử dụng (hành động r) thì chương trình có vấn đề và trạng thái của chương trình là A. Ngược lại, trạng thái U vẫn được giữ nguyên nếu các câu lệnh tiếp theo vẫn chưa chứa lệnh gán giá trị cho biến này (hành động u). Cho đến khi gặp câu lệnh gán giá trị cho biến này (hành động d), trạng thái của chương trình được chuyển thành D. Nếu biến này được sử dụng ở các câu lệnh tiếp theo (hành LUAN VAN CHAT LUONG download : add luanvanchat@agmail.com 22 động r) thì trạng thái của chương trình chuyển thành R.
Ngược lại, nếu các câu lệnh tiếp theo lại gán lại giá trị cho biến (hành động d) hoặc khai báo lại biến này và không gán giá trị cho nó (hành động u) thì xảy ra vấn đề và trạng thái của chương trình là A. Tại trạng thái này, mọi hành động (d, u và r) xảy ra đều không thay đổi trạng thái của chương trình. Tại trạng thái R, nếu biến này vẫn tiếp tục được sử dụng ở các lệnh tiếp theo (hành động r) thì trạng thái của chương trình vẫn không thay đổi. Ngược lại, nếu xuất hiện câu lệnh gán lại giá trị cho biến (hành động d) thì trạng thái của chương trình quay về D.
Trong trường hợp xuất hiện câu lệnh khai báo lại biến này và không gán giá trị cho nó (hành động u) thì chương trình được chuyển từ trạng thái R sang trạng thái U. Như vậy, các vấn đề với dòng dữ liệu thuộc loại 1 ứng với trường hợp dd xảy ra trong sơ đồ chuyển trạng thái. Các vấn đề thuộc loại 2 ứng với trường hợp ur và loại 3 ứng với trường hợp du. Để phát hiện các vấn đề này, chúng ta sẽ tiến hành xây dựng sơ đồ chuyển trạng thái ứng với mỗi biến như Hình 2.
Nếu trạng thái A xuất hiện thì chương trình có vấn đề về dòng dữ liệu. Trong trường hợp này, chúng ta cần kiểm tra lại mã nguồn, tìm nguyên nhân của tình huống này và sửa lỗi. Tuy nhiên, cho dù trạng thái lỗi (trạng thái A) không xuất hiện trong quá trình phân tích chương trình, chúng ta vẫn không đảm bảo được rằng chương trình không còn lỗi. Các lỗi có thể xảy ra trong quá trình gán/gán lại giá trị cho các biến và trong quá trình sử dụng chúng (trong các câu lệnh tính toán, trong các biểu thức điều kiện…).