NỘI DUNG BÀI HỌC
✅ Nắm được triết lý tách biệt WHAT (nghiệp vụ) và HOW (kỹ thuật) trong POM.
✅ Biết cách xây dựng BasePage để gom logic chung.
✅ Tạo được Page Object riêng cho từng trang web.
✅ Biết kết nối POM với Pytest Fixture để viết test ngắn gọn, dễ bảo trì.
✅ Thực hành tạo một LoginPage và InventoryPage hoàn chỉnh.
I. VẤN ĐỀ: TEST KHÔNG CÓ KIẾN TRÚC
1. Định nghĩa
Code rác (Unstructured Test Code) là cách viết test trực tiếp bằng Playwright API trong cùng một file, trộn lẫn giữa thao tác kỹ thuật và logic nghiệp vụ.
Ví dụ:
def test_login(page):
page.goto("https://www.saucedemo.com/")
page.locator("#user-name").fill("standard_user")
page.locator("#password").fill("secret_sauce")
page.locator("#login-button").click()
expect(page).to_have_url("https://www.saucedemo.com/inventory.html")
2. Hệ quả
| Vấn đề | Mô tả | Tác động |
|---|---|---|
| Locator trùng lặp | Dùng cùng một selector ở nhiều nơi | Khi UI thay đổi phải sửa hàng loạt test |
| Lẫn lộn nghiệp vụ và kỹ thuật | Code test chứa cả hành động kỹ thuật (click, fill) và ý định nghiệp vụ (đăng nhập) |
Người đọc khó hiểu test đang kiểm tra điều gì |
| Mất tính tái sử dụng | Phải viết lại thao tác tương tự cho nhiều test | Tốn thời gian, dễ lỗi |
3. Nguyên tắc DRY (Don’t Repeat Yourself)
Định nghĩa: Không lặp lại cùng một đoạn mã hoặc logic ở nhiều nơi.
Mục tiêu: Khi một hành vi (như login) thay đổi, chỉ cần chỉnh ở một vị trí duy nhất.
Ý nghĩa trong automation: Đảm bảo test framework dễ bảo trì, nhất quán và mở rộng lâu dài.
II. KHÁI NIỆM PAGE OBJECT MODEL (POM)
1. Định nghĩa
Page Object Model (POM) là một mô hình thiết kế (Design Pattern) dùng trong kiểm thử tự động, trong đó mỗi trang web hoặc component được biểu diễn bằng một lớp (class) riêng biệt.
Đặc điểm:
-
Mỗi class đại diện cho một trang UI cụ thể.
-
Class chứa:
-
Tập hợp các locator.
-
Các hành động nghiệp vụ (business actions) liên quan đến trang đó.
-
2. Mục tiêu
-
Tách biệt WHAT và HOW:
-
WHAT: Ý định nghiệp vụ (“đăng nhập thành công”)
-
HOW: Cách thao tác kỹ thuật (“nhập username”, “click nút login”)
-
-
Giảm lặp lại code: Các hành động UI chỉ được định nghĩa một lần.
-
Tăng khả năng bảo trì: Khi locator thay đổi, chỉ cần cập nhật trong Page Object tương ứng.
-
Dễ đọc và dễ mở rộng: Test thể hiện ý định nghiệp vụ thay vì thao tác kỹ thuật.
3. Ví dụ minh họa
| Thành phần | Vai trò | Ví dụ |
|---|---|---|
| Page Object | Đại diện cho một trang web | LoginPage, InventoryPage |
| BasePage | Gom logic kỹ thuật chung | _click(), _fill(), _visit() |
| Business Action | Hành động có ý nghĩa nghiệp vụ | login(), add_item_to_cart() |
III. CẤU TRÚC CHUẨN CỦA FRAMEWORK POM
| Lớp | Nhiệm vụ chính | Ví dụ |
|---|---|---|
| BasePage | Chứa các thao tác Playwright cấp thấp, có thể tái sử dụng | _click(), _fill(), _visit() |
| Page Object | Mô tả nghiệp vụ của một trang cụ thể, kế thừa BasePage | LoginPage.login(), InventoryPage.add_to_cart() |
| Test Case | Gọi các hành động nghiệp vụ để kiểm thử chức năng | test_login_successful() |
IV. BASEPAGE – NỀN TẢNG KỸ THUẬT CHUẨN HÓA HÀNH ĐỘNG
1. Định nghĩa
BasePage là lớp cha trừu tượng, chứa các hành động cơ bản nhất của Playwright.
Tất cả các Page Object khác đều kế thừa từ lớp này để sử dụng lại các thao tác chuẩn hóa.
2. Chức năng
-
Gom nhóm các hàm Playwright thường dùng (
goto,click,fill,assert) -
Thêm logic phụ trợ: logging, xử lý lỗi, timeout, hoặc wait tùy chỉnh.
-
Đảm bảo các Page Object tuân thủ cùng một chuẩn hành động.
3. Triển khai – pages/base_page.py
from playwright.sync_api import Page, expect, Locator, TimeoutError
class BasePage:
"""Lớp cha chứa các hành động Playwright cơ bản, kế thừa cho mọi Page Object."""
def __init__(self, page: Page):
self.page = page
def _visit(self, url: str):
"""Điều hướng tới URL được chỉ định."""
print(f"[BasePage] Truy cập: {url}")
self.page.goto(url, wait_until="domcontentloaded")
def _get_locator(self, locator: str) -> Locator:
"""Trả về đối tượng Locator từ chuỗi selector."""
return self.page.locator(locator)
def _click(self, locator: str, name: str = ""):
"""Thực hiện click với xử lý lỗi và ghi log."""
try:
print(f"[Click] {name or locator}")
self._get_locator(locator).click()
except TimeoutError:
print(f"[Lỗi] Không thể click vào {locator}")
raise
def _fill(self, locator: str, text: str, name: str = ""):
"""Điền dữ liệu vào ô input."""
print(f"[Fill] '{text}' vào {name or locator}")
self._get_locator(locator).fill(text)
def _assert_text_visible(self, locator: str, text: str):
"""Kiểm tra văn bản mong đợi hiển thị trên giao diện."""
print(f"[Assert] Kiểm tra '{text}' hiển thị")
expect(self._get_locator(locator)).to_contain_text(text)
V. PAGE OBJECT – BIỂU DIỄN NGHIỆP VỤ TRÊN GIAO DIỆN
1. Định nghĩa
Page Object là một lớp (class) mô tả toàn bộ hành vi nghiệp vụ của một trang web cụ thể.
Mỗi Page Object gồm hai phần chính:
-
Locators – tất cả các selector (CSS/XPath) được khai báo ở dạng hằng số.
-
Business Actions – các hành động nghiệp vụ mô phỏng tương tác người dùng.
2. Mục tiêu
-
Gom nhóm tất cả các thao tác liên quan đến một trang duy nhất.
-
Giúp test chỉ gọi đến các hành động nghiệp vụ thay vì mã kỹ thuật chi tiết.
-
Khi UI thay đổi, chỉ cập nhật trong Page Object tương ứng.
3. Ví dụ – pages/login_page.py
from .base_page import BasePage
from playwright.sync_api import expect
class LoginPage(BasePage):
"""Đại diện cho trang đăng nhập của hệ thống."""
# Locators (được định nghĩa như hằng số)
URL = "https://www.saucedemo.com/"
USERNAME_FIELD = "#user-name"
PASSWORD_FIELD = "#password"
LOGIN_BUTTON = "#login-button"
ERROR_MESSAGE = "[data-test='error']"
# Business Actions
def goto(self):
"""Điều hướng tới trang Login."""
self._visit(self.URL)
def login(self, username, password):
"""Thực hiện nghiệp vụ đăng nhập."""
self.goto()
self._fill(self.USERNAME_FIELD, username, name="Username")
self._fill(self.PASSWORD_FIELD, password, name="Password")
self._click(self.LOGIN_BUTTON, name="Login Button")
def assert_login_successful(self):
"""Xác minh đăng nhập thành công."""
expect(self.page).to_have_url("https://www.saucedemo.com/inventory.html")
def assert_error_message_visible(self, expected_text):
"""Kiểm tra thông báo lỗi đăng nhập hiển thị đúng."""
self._assert_text_visible(self.ERROR_MESSAGE, expected_text)
1. Cấu trúc Test
Test case chỉ nên mô tả luồng nghiệp vụ thay vì thao tác kỹ thuật.
Không được chứa Playwright API trực tiếp như locator, click, fill.
2. Ví dụ – tests/test_login_pom.py
3. Đặc điểm
| Tiêu chí | Đặc điểm của test sạch |
|---|---|
| Ngắn gọn | Không chứa locator hoặc lệnh Playwright thô |
| Dễ đọc | Mô tả rõ ý định kiểm thử bằng ngôn ngữ nghiệp vụ |
| Dễ bảo trì | Khi UI thay đổi, test không cần chỉnh sửa |
| Dễ mở rộng | Có thể thêm trang hoặc nghiệp vụ khác mà không ảnh hưởng test cũ |
VII. MỞ RỘNG: PAGE OBJECT CHO TRANG KHÁC
1. Khái niệm
Khi ứng dụng có nhiều trang, mỗi trang cần có Page Object riêng biệt, kế thừa BasePage.
Ví dụ: InventoryPage, CartPage, CheckoutPage.
2. Ví dụ – pages/inventory_page.py
VIII. TỔNG KẾT KHÁI NIỆM TRONG POM
| Khái niệm | Định nghĩa | Ý nghĩa trong automation |
|---|---|---|
| POM (Page Object Model) | Mô hình tổ chức test trong đó mỗi trang được biểu diễn bằng một class | Giúp tách biệt nghiệp vụ và kỹ thuật, dễ bảo trì |
| BasePage | Lớp cha chứa hành động cơ bản của Playwright | Chuẩn hóa thao tác, tránh lặp lại mã |
| Page Object | Class đại diện cho một trang cụ thể | Gom locator và hành động nghiệp vụ tại một nơi |
| Business Action | Hành động có ý nghĩa nghiệp vụ (vd: login, add_to_cart) | Là “ngôn ngữ” của test case, giúp test dễ đọc |
| Locator | Selector trỏ tới element trong UI | Quản lý tập trung, dễ thay đổi khi UI đổi |
| Test sạch (Clean Test) | Test chỉ mô tả nghiệp vụ, không chứa chi tiết kỹ thuật | Dễ đọc, dễ hiểu, dễ mở rộng |
IX. BÀI TẬP THỰC HÀNH
Trang web: https://www.saucedemo.com/
1. Mục tiêu
-
Tạo cấu trúc thư mục
pages/vàtests/theo chuẩn POM. -
Viết
BasePagevàLoginPagehoàn chỉnh. -
Tạo thêm
InventoryPagemô phỏng hành vi thêm sản phẩm vào giỏ. -
Viết test case đăng nhập → thêm sản phẩm → xác minh giỏ hàng.
2. Tiêu chí đánh giá
| Tiêu chí | Mô tả đạt yêu cầu |
|---|---|
| Cấu trúc 3 lớp | Có BasePage, LoginPage, InventoryPage rõ ràng |
| Locator tập trung | Không chứa locator trong test |
| Test rõ nghiệp vụ | Test mô tả logic “login + add to cart” bằng ngôn ngữ tự nhiên |
| Code dễ đọc | Có log, tên hàm rõ ràng, không lặp thao tác Playwright |
X. KẾT LUẬN
Page Object Model là nền tảng cốt lõi để xây dựng framework kiểm thử tự động bền vững.
Nó giúp tách biệt giữa logic kỹ thuật và nghiệp vụ, giảm thiểu trùng lặp mã, và tạo ra test dễ đọc, dễ mở rộng.
Việc nắm vững POM giúp học viên bước đầu hình thành tư duy kiến trúc framework, thay vì chỉ “ghi script chạy được”.
