Bài F16. Kiểm thử và gỡ lỗi chương trình

Nội dung lý thuyết

1. Một số lỗi thường gặp trong chương trình

a) Phân loại lỗi của chương trình

  • Lỗi cú pháp: Là lỗi sai do viết câu lệnh bị sai với cú pháp của ngôn ngữ lập trình. Ví dụ:
s = "Tin học ' bị lỗi SyntaxError vì cặp dấu bắt đầu và kết thúc xâu kí tự khác nhau.
  • Lỗi thời gian chạy: Lỗi xảy ra khi một lệnh không thực hiện được trong thời gian chạy chương trình. Ví dụ:

a = 1 / b

Nếu b bằng 0 thì sẽ gây lỗi ZeroDivisionError.

  • Lỗi logic: Lỗi sai trong chương trình khiến kết quả không đúng mong đợi hoặc chương trình bị lặp vô tận. Ví dụ:

delta = b**2 + 4*a*c  # Sai logic vì lệnh đúng là delta = b**2 - 4*a*c

b) Một số thông báo lỗi thường gặp

Khi gặp lỗi cú pháp hoặc lỗi thời gian chạy, máy sẽ dừng lại và hiển thị thông báo lỗi. Một số lỗi thường gặp gồm:

  • SyntaxError: Lỗi cú pháp. Ví dụ:
a = 1.o  # Sai

Lỗi: SyntaxError: invalid decimal literal
→ Sửa: a = 1.0

  • NameError: Lỗi gọi tên không tồn tại. Ví dụ:

prin("Chào bạn")  # Sai

Lỗi: NameError: name 'prin' is not defined. Did you mean: 'print'?
→  Sửa: print("Chào bạn")

  •  IndexError: Lỗi truy cập phần tử ngoài chỉ số mảng. Ví dụ:

A = [6,7,8]; print(A[4])  # Sai

Lỗi: IndexError: list index out of range

  • TypeError: Lỗi do sai kiểu dữ liệu. Ví dụ:

a = 1 + "234"  # Sai

Lỗi: TypeError: unsupported operand type(s) for +: 'int' and 'str'

  • ValueError: Lỗi giá trị không hợp lệ. Ví dụ:
a = int("12o")  # Sai

Lỗi: ValueError: invalid literal for int() with base 10: '12o'
→ Sửa: a = int("120")

  • IndentationError: Lỗi do thụt đầu dòng sai quy định. Ví dụ:
for i in range(5):
print(i)  # Sai

Lỗi: IndentationError: expected an indented block after 'for' statement
→ Sửa: thêm thụt lề vào dòng lệnh trong vòng lặp.

2. Kiểm thử chương trình và gỡ lỗi

Kiểm thử chương trình nhằm phát hiện và sửa lỗi (cú pháp, thời gian chạy, logic) thông qua kiểm thử.

a) Kiểm thử chương trình

  • Kiểm thử chương trình là quá trình chạy chương trình với các bộ dữ liệu đầu vào khác nhau để kiểm tra và phát hiện lỗi logic. Mỗi bộ dữ liệu đầu vào gọi là một trường hợp kiểm thử, tập hợp các trường hợp kiểm thử gọi là bộ kiểm thử.

  • Cách thực hiện: Chạy chương trình với các đầu vào cụ thể và quan sát kết quả. Nếu chương trình cho kết quả sai thì cần tìm và sửa lỗi tương ứng.

Ví dụ 1: Kiểm thử chương trình giải phương trình ax + b = 0

a = float(input("Nhập a: "))
b = float(input("Nhập b: "))
x = -b/a
print("Nghiệm x =", x)
  • Nếu nhập ký tự không hợp lệ (vd: 'ab'), chương trình báo lỗi cú pháp.

  • Nếu nhập a = 0 thì bị lỗi logic (chia cho 0).

  • Cần sửa lại:

a = float(input("Nhập a: "))
b = float(input("Nhập b: "))
x = -b/a
print("Nghiệm x =", x)

Ví dụ 2: Kiểm thử chương trình tìm GTLN trong mảng A

- Bộ kiểm thử 1:

TC1: A = [5]
TC2: A = [2, 5, 4]

→ Cho kết quả đúng.

- Bộ kiểm thử 2:

TC3: A = [2, 5, 4, 3]
TC4: A = []

→ TC4 sai do mảng rỗng → cần bổ sung kiểm tra điều kiện rỗng.

- Bộ kiểm thử 3:

TC5: A = [2, 5, 4, 3]
TC6: A = [-2]

→ TC6 sai do mảng chỉ có phần tử âm → logic sai khi gán gtLonNhat = 0.

b) Gỡ lỗi chương trình

  • Mục tiêu: Sửa chương trình dựa trên các lỗi được phát hiện trong quá trình kiểm thử.

Ví dụ gỡ lỗi với TC4:

def timGTLonNhat(A):
    if A == []:
        raise ValueError("Mảng rỗng.")  # Gỡ lỗi TC4
    gtLonNhat = A[0]
    for i in range(1, len(A)):
        if A[i] > gtLonNhat:
            gtLonNhat = A[i]
    return gtLonNhat
A = list(map(int, input("Nhập mảng A: ").split()))
print("Giá trị lớn nhất là", timGTLonNhat(A))

Gỡ lỗi với TC6: Sai vì gán gtLonNhat = 0, cần sửa thành gtLonNhat = A[0].

3. Cách tìm lỗi trong chương trình

Giúp phát hiện lỗi bằng cách thêm lệnh print() và sử dụng công cụ Debugger trong Python.

a) Thêm các lệnh print() vào chương trình

  • Cách làm: Thêm print() vào mã nguồn để theo dõi quá trình thay đổi giá trị biến → xác định vị trí và nguyên nhân gây lỗi.

Ví dụ 4: Với bộ kiểm thử TC6: A = [-2], thêm lệnh print() để theo dõi biến:

for i in range(len(A)):
    print(f'gtLonNhat = {gtLonNhat}, A[{i}] = {A[i]}', end = ' -> ')
    if gtLonNhat < A[i]:
        gtLonNhat = A[i]
        print(f'gtLonNhat = {gtLonNhat}')
  • Kết quả:
gtLonNhat = 0, A[0] = -2 -> Giá trị lớn nhất là 0.

→ Dựa vào đó xác định lỗi do dòng gtLonNhat = 0 và sửa thành gtLonNhat = A[0].

b) Sử dụng công cụ trình gỡ lỗi (Debugger) trong Python

  • Lý do dùng: Không cần chỉnh sửa mã nguồn như khi dùng print().

  • Thực hiện trong IDLE Shell:
    Các bước:

    1. Chọn DebugDebugger
    2. Mở chương trình cần kiểm thử
    3. Chọn RunRun Module (F5) để bắt đầu gỡ lỗi

Minh họa các bước thực hiện gỡ lỗi chương trình

  • Debug Control:

    • Dùng Step để chạy từng lệnh

    • Dùng Over để kết thúc hàm

    • Dùng Out để kết thúc toàn bộ gỡ lỗi

Ví dụ 5: Gỡ lỗi chương trình tính chu vi, diện tích hình tròn

r = int(input("Nhập bán kính r: "))
cvTron = 2 * pi * r
dtTron = pi * r ** 2
print(f"Chu vi hình tròn là: {cvTron}")
print(f"Diện tích hình tròn là: {dtTron}")
  • Lỗi: Chạy đến dòng 2 báo "name 'pi' is not defined" Nguyên nhân: Chưa import thư viện math

  • Cách sửa: Thêm dòng: from math import pi