NỘI DUNG BÀI HỌC
✅ Nắm vững và vận dụng thành thạo toàn bộ khối lệnh
try
, except
, else
, và finally
. ✅ Biết cách bắt và xử lý nhiều loại lỗi cụ thể (
Specific Exceptions
) để kịch bản linh hoạt hơn. ✅ Chủ động tạo ra lỗi một cách có chủ đích bằng từ khóa
raise
để kiểm soát luồng chương trình. ✅ Xây dựng được các hàm automation "an toàn" có khả năng tự xử lý các tình huống không mong muốn.
1. Tại sao phải xử lý lỗi? Kịch bản "giòn tan" vs. Kịch bản "bền bỉ"
Hãy tưởng tượng bạn đang viết một kịch bản automation để kiểm tra 100 test case.
-
Kịch bản "giòn tan" (Brittle Script): Chạy đến test case thứ 5, một pop-up quảng cáo bất ngờ xuất hiện làm script không tìm thấy nút "Thanh toán". Script báo lỗi đỏ lè và dừng lại ngay lập tức. Bạn mất trắng kết quả của 95 test case còn lại.
-
Kịch bản "bền bỉ" (Robust Script): Chạy đến test case thứ 5, kịch bản cũng không tìm thấy nút "Thanh toán". Nhưng thay vì dừng lại, nó được lập trình để:
-
Thử (
try
) tìm nút. -
Phát hiện lỗi (
except
)NoSuchElementException
. -
Bên trong
except
, nó kiểm tra xem có pop-up quảng cáo không. Nếu có, nó đóng pop-up đi. -
Thử tìm lại nút "Thanh toán" một lần nữa.
-
Báo cáo test case thứ 5 là FAILED nhưng tiếp tục chạy 95 test case còn lại.
-
Xử lý lỗi (Exception Handling) chính là công cụ giúp chúng ta biến kịch bản từ "giòn tan" thành "bền bỉ".
2. Khối lệnh try...except
- Lưới an toàn của bạn
Đây là cấu trúc cơ bản nhất để "bẫy" lỗi, ngăn không cho chương trình bị dừng đột ngột.
-
try
: Đặt đoạn code mà bạn dự đoán có khả năng gây ra lỗi vào trong khối này. -
except
: Nếu có lỗi xảy ra trong khốitry
, chương trình sẽ bỏ qua phần còn lại củatry
và nhảy ngay đến khốiexcept
để thực thi.
2.1 So sánh try-except
(Python) và try-catch
(ngôn ngữ khác)
Nếu bạn đã từng lập trình với các ngôn ngữ như Java, C#, C++ hay JavaScript, bạn sẽ quen thuộc với cú pháp try-catch
. Trong Python, cơ chế xử lý lỗi hoàn toàn tương tự về mặt chức năng, nhưng sử dụng từ khóa khác: try-except
.
Về bản chất, chúng là một. Nếu bạn hiểu try-catch
, bạn đã hiểu 90% về try-except
. Chỉ cần nhớ rằng trong thế giới Python, chúng ta dùng except
thay cho catch
.
Bảng so sánh nhanh:
Tiêu chí | Python (try-except) | Ngôn ngữ khác (ví dụ: Java, C# - try-catch) |
Từ khóa chính | try, except, else, finally | try, catch, finally |
Bắt lỗi | except ValueError as e: | catch (ValueError e) { ... } |
Bắt nhiều lỗi | except (ValueError, TypeError): | Thường dùng nhiều khối catch riêng biệt hoặc các cú pháp khác tùy ngôn ngữ. |
Mục đích | Hoàn toàn giống nhau: "bẫy" các lỗi xảy ra trong khối try để chương trình không bị dừng đột ngột. | Hoàn toàn giống nhau: "bẫy" các lỗi xảy ra trong khối try để chương trình không bị dừng đột ngột. |
2.2 Bắt một loại lỗi cụ thể
Việc chỉ định rõ loại lỗi bạn muốn bắt (ZeroDivisionError
, ValueError
, NoSuchElementException
) là một thói quen rất tốt, giúp code rõ ràng và xử lý đúng vấn đề.
-
🔹 Ví dụ trong cuộc sống: Một máy bán hàng tự động.
-
try
: Bạn đưa tiền và chọn món. -
except PaymentError
: Nếu máy không nhận tiền, nó báo "Lỗi thanh toán". -
except OutOfStockError
: Nếu món hàng đã hết, nó báo "Sản phẩm tạm hết hàng".
try: age_input = input("Vui lòng nhập tuổi của bạn: ") age = int(age_input) if age < 0: print("Tuổi không thể là số âm.") else: print(f"Bạn {age} tuổi.") except ValueError: # Lỗi này xảy ra khi int() không thể chuyển đổi chuỗi thành số (ví dụ: người dùng nhập "abc") print("Lỗi: Dữ liệu nhập vào không phải là một con số hợp lệ.")
-
-
🔹 Ứng dụng trong Automation: Xử lý tình huống một element không tồn tại trên trang.
from selenium.common.exceptions import NoSuchElementException # Giả sử `driver` là một đối tượng trình duyệt try: # Cố gắng tìm và click vào pop-up quảng cáo close_button = driver.find_element(By.ID, "close-popup-btn") close_button.click() print("Đã tìm thấy và đóng pop-up quảng cáo.") except NoSuchElementException: # Chỉ xử lý khi element không được tìm thấy print("Thông báo: Không có pop-up nào xuất hiện, tiếp tục các bước tiếp theo.")
✍️ Bài tập thực hành phần 2.2
-
Tính toán an toàn: Viết chương trình chia 2 số a và b do người dùng nhập. Dùng
try-except
riêng biệt để bắt lỗiValueError
(nếu nhập chữ) vàZeroDivisionError
(nếu chia cho 0) với các thông báo lỗi tương ứng.
2.3 Bắt nhiều loại lỗi cùng lúc
Bạn có thể bắt nhiều loại exception trong cùng một khối except
bằng cách đặt chúng trong một tuple.
-
🔹 Ví dụ trong cuộc sống: Bạn thử gọi điện cho một người bạn.
-
try
: Bấm số và gọi. -
except (NoSignalError, LowBatteryError)
: Nếu không có sóng hoặc hết pin, bạn đều không thể gọi được và sẽ thử lại sau.
try: my_dict = {"name": "John"} key = input("Nhập key bạn muốn truy cập: ") # Ví dụ: 'age' print(my_dict[key]) except (KeyError, IndexError) as e: # Bắt cả hai lỗi: truy cập key không tồn tại trong dict, hoặc chỉ số ngoài phạm vi trong list print(f"Lỗi truy cập dữ liệu: {e}")
-
-
🔹 Ứng dụng trong Automation: Khi một hành động có thể thất bại vì nhiều lý do. Ví dụ, việc click một nút có thể thất bại vì không tìm thấy nó, hoặc tìm thấy nhưng bị che khuất, hoặc element đã bị "lỗi thời" (stale).
from selenium.common.exceptions import NoSuchElementException, ElementClickInterceptedException, StaleElementReferenceException try: button = driver.find_element(By.CSS_SELECTOR, "#submit-btn") button.click() except (NoSuchElementException, ElementClickInterceptedException, StaleElementReferenceException) as e: print(f"Không thể click vào nút submit. Lý do: {type(e).__name__}") # type(e).__name__ sẽ cho bạn biết tên của lớp Exception, ví dụ: 'NoSuchElementException'
✍️ Bài tập thực hành phần 2.3-
Đọc file linh hoạt: Viết code để mở và đọc một file có tên do người dùng nhập. Dùng một khối
except
duy nhất để bắt cả hai lỗiFileNotFoundError
(file không tồn tại) vàPermissionError
(không có quyền đọc file).
-
3. Hoàn thiện quy trình với else
và finally
-
else
: Chỉ được thực thi khi khốitry
chạy thành công và không gây ra lỗi nào. -
finally
: Luôn luôn được thực thi, bất kể có lỗi hay không. Đây là nơi hoàn hảo cho các hành động "dọn dẹp". -
🔹 Ví dụ trong cuộc sống: Giao dịch tại ATM.
-
try
: Yêu cầu rút 1,000,000đ. -
except InsufficientFundsError
: Nếu không đủ tiền, máy báo lỗi. -
else
: Nếu rút tiền thành công, máy in biên lai. -
finally
: Bất kể thành công hay thất bại, máy luôn trả lại thẻ cho bạn.
try: f = open("config.ini", "r") except FileNotFoundError: print("Lỗi: Không tìm thấy file config.ini.") else: # Chỉ chạy nếu file được mở thành công print("Đọc file config thành công.") # ... xử lý nội dung file ... f.close() # Đóng file trong else cũng là một cách finally: # Luôn chạy, dù có lỗi hay không print("--- Kết thúc quá trình xử lý cấu hình ---")
-
-
🔹 Ứng dụng trong Automation: Đây là cấu trúc VÀNG để đảm bảo sự ổn định và sạch sẽ của test case.
try: print("Bắt đầu test case: Thêm sản phẩm vào giỏ hàng") # 1. Tìm sản phẩm # 2. Click nút "Thêm vào giỏ" # 3. Chờ và xác nhận thông báo thành công xuất hiện assert "Thêm vào giỏ hàng thành công" in driver.page_source except Exception as e: # Nếu bất kỳ bước nào ở trên thất bại print(f"❌ TEST FAILED: {e}") else: # Chỉ chạy nếu tất cả các bước trong try đều thành công print("✅ TEST PASSED: Sản phẩm đã được thêm vào giỏ hàng thành công.") finally: # Luôn luôn thực hiện để dọn dẹp print("Đang chụp ảnh màn hình kết quả...") driver.save_screenshot("add_to_cart_result.png") # driver.quit() # Đóng trình duyệt sau khi test xong
#Selenium – tìm element try: btn = driver.find_element(By.ID, "login") btn.click() except NoSuchElementException: print("❌ Không tìm thấy nút login") finally: driver.quit()
#Data-driven test – đọc test data từ file try: with open("testdata.csv", "r") as f: print(f.readlines()) except FileNotFoundError: print("❌ Không tìm thấy file test data")
✍️ Bài tập thực hành phần 3
-
Xác nhận và Dọn dẹp: Mở rộng bài tập tính toán an toàn ở phần 2.2. Dùng khối
else
để in ra kết quả phép chia chỉ khi không có lỗi. Dùng khốifinally
để luôn luôn in ra "Chương trình tính toán kết thúc."
4. Chủ động báo lỗi với raise
Đôi khi, bạn muốn chương trình của mình tự tạo ra một lỗi khi một điều kiện logic nào đó không được đáp ứng. raise
cho phép bạn làm điều đó.
-
🔹 Ví dụ trong cuộc sống: Bạn đi khám bệnh, bác sĩ (
hàm
) kiểm tra nhiệt độ (dữ liệu
) của bạn. Nếu nhiệt độ trên 38°C (điều kiện không hợp lệ
), bác sĩ sẽ "raise" một cảnh báo "Bệnh nhân bị sốt!" để y tá xử lý.def set_age(age): if not isinstance(age, int): raise TypeError("Tuổi phải là một số nguyên.") if age < 0: raise ValueError("Tuổi không thể là một số âm.") print(f"Tuổi đã được đặt là: {age}") try: set_age(-5) except (TypeError, ValueError) as e: print(f"Lỗi khi đặt tuổi: {e}")
-
🔹 Ứng dụng trong Automation: Khi bạn viết một hàm tiện ích, và muốn nó báo hiệu một cách rõ ràng khi gặp phải tình huống không thể xử lý.
def get_element_text(driver, locator): """Hàm này lấy text của element, nhưng sẽ báo lỗi nếu element rỗng.""" try: element = driver.find_element(*locator) # *locator dùng để giải nén tuple (By.ID, "some_id") text = element.text.strip() if text == "": # Element tồn tại nhưng không có text, đây là một lỗi logic raise ValueError(f"Element tại {locator} không chứa text.") return text except NoSuchElementException: # Ném lại lỗi để báo cho nơi gọi hàm biết rằng element không tồn tại raise NoSuchElementException(f"Không tìm thấy element với locator: {locator}") # Cách sử dụng try: welcome_message = get_element_text(driver, (By.ID, "welcome-msg")) print(f"Thông điệp chào mừng: {welcome_message}") except (NoSuchElementException, ValueError) as e: print(f"Không thể lấy thông điệp chào mừng. Lý do: {e}")
5. Mini Quiz 🎯
-
Trong Python dùng từ khóa nào để bẫy lỗi?
-
finally
có chạy khi trongtry
bị lỗi không? -
Khi nào
else
được chạy? -
Điểm khác biệt chính giữa try–catch (Java/C#) và try–except (Python)?
-
Output của code sau?
try: print(5/0) except ZeroDivisionError: print("Lỗi chia cho 0") finally: print("Kết thúc")
6. Bài tập tổng hợp cuối buổi
Bài 1: Nhập số
Viết chương trình yêu cầu người dùng nhập số.
-
Nếu nhập đúng → in bình phương.
-
Nếu nhập sai → in
"Sai định dạng"
.
Bài 2: Máy tính an toàn
Viết hàm safe_divide(a, b)
chia 2 số.
-
Nếu
b = 0
→ trả về"Không thể chia cho 0"
. -
Ngược lại → trả về kết quả.
Bài 3: File
Đọc file data.txt
.
-
Nếu file tồn tại → in nội dung.
-
Nếu không → in
"File không tồn tại"
. -
Luôn in
"Kết thúc chương trình"
.
Bài 4: Automation
-
Giả lập tìm element
"submit"
. -
Nếu không tìm thấy → in
"Không tìm thấy element"
. -
Luôn in
"Đóng trình duyệt"
.
👉 Đây là một hàm tiện ích cực kỳ phổ biến trong các framework automation thực tế, giúp bạn kết hợp tất cả kiến thức đã học để tạo ra một kịch bản mạnh mẽ và dễ gỡ lỗi.