Sử dụng Chat AI để generate code Test Automation

Anh Tester chỉ các bạn sử dụng các model Chat AI hiện nay để hỗ trợ generate code Test Automation một cách nhanh chóng hiệu quả khi viết code test automation với nhiều framework hay ngôn ngữ lập trình khác nhau.

Các bạn xem video Anh Tester hướng dẫn chi tiết từng bước nhé !!

1. Các model Chat AI

ChatGPT: https://chatgpt.com/
Gemini: https://gemini.google.com/app
Claude: https://claude.ai/new
Deepseek: https://chat.deepseek.com/

Đặc biệt con Claude chuyên cho Code. Mà con này tốn phí nên cũng hơi tiếc đối với những bạn chưa trả phí được.

2. Cách sử dụng "prompt" cụ thể để generate code Test Automation

Sử dụng câu hỏi thông thường và đề cập đến trang web cụ thể và thư viện cụ thể để Chat AI hiểu được và generate code cho mình như mong muốn. (chỗ này muốn chi tiết luôn thì đưa nó Account login, nhưng cần cân nhắc 😝, có thể dùng xong đổi account liền)

Và có thể áp dụng đối với nhiều con Chat AI cùng lúc để xem kết quả con AI nào như ý muốn thì dùng.

✳️"Bạn giúp tôi generate code Page Object Model cho trang Login https://crm.anhtester.com/admin/authentication sử dụng thư viện Selenium Java và TestNG Framework trong Maven project."

⭐️Kết quả khi dùng Claude như sau:



Tôi sẽ giúp bạn tạo code Page Object Model (POM) cho trang Login của https://crm.anhtester.com/admin/authentication sử dụng Selenium Java và TestNG trong một dự án Maven.

Login Page Object Model với Selenium và TestNG
package pages;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.time.Duration;

public class LoginPage {

    private WebDriver driver;
    private WebDriverWait wait;

    // URL của trang login
    private final String LOGIN_PAGE_URL = "https://crm.anhtester.com/admin/authentication";

    // Định nghĩa các element trên trang Login bằng @FindBy
    @FindBy(id = "email")
    private WebElement emailInput;

    @FindBy(id = "password")
    private WebElement passwordInput;

    @FindBy(css = "button[type='submit']")
    private WebElement loginButton;

    @FindBy(css = ".alert-danger")
    private WebElement errorMessage;

    @FindBy(xpath = "//a[contains(text(),'Forgot Password?')]")
    private WebElement forgotPasswordLink;

    @FindBy(css = ".company-logo")
    private WebElement companyLogo;

    // Khởi tạo các element với PageFactory
    public LoginPage(WebDriver driver) {
        this.driver = driver;
        this.wait = new WebDriverWait(driver, Duration.ofSeconds(15));
        PageFactory.initElements(driver, this);
    }

    // Mở trang Login
    public LoginPage openLoginPage() {
        driver.get(LOGIN_PAGE_URL);
        wait.until(ExpectedConditions.visibilityOf(emailInput));
        return this;
    }

    // Nhập email
    public LoginPage enterEmail(String email) {
        wait.until(ExpectedConditions.visibilityOf(emailInput));
        emailInput.clear();
        emailInput.sendKeys(email);
        return this;
    }

    // Nhập password
    public LoginPage enterPassword(String password) {
        wait.until(ExpectedConditions.visibilityOf(passwordInput));
        passwordInput.clear();
        passwordInput.sendKeys(password);
        return this;
    }

    // Click vào nút Login
    public DashboardPage clickLoginButton() {
        wait.until(ExpectedConditions.elementToBeClickable(loginButton));
        loginButton.click();
        return new DashboardPage(driver);
    }

    // Thực hiện đăng nhập
    public DashboardPage login(String email, String password) {
        enterEmail(email);
        enterPassword(password);
        return clickLoginButton();
    }

    // Click vào link "Forgot Password"
    public ForgotPasswordPage clickForgotPasswordLink() {
        wait.until(ExpectedConditions.elementToBeClickable(forgotPasswordLink));
        forgotPasswordLink.click();
        return new ForgotPasswordPage(driver);
    }

    // Kiểm tra xem thông báo lỗi có hiển thị không
    public boolean isErrorMessageDisplayed() {
        try {
            wait.until(ExpectedConditions.visibilityOf(errorMessage));
            return errorMessage.isDisplayed();
        } catch (Exception e) {
            return false;
        }
    }

    // Lấy nội dung thông báo lỗi
    public String getErrorMessage() {
        wait.until(ExpectedConditions.visibilityOf(errorMessage));
        return errorMessage.getText();
    }

    // Kiểm tra xem logo công ty có hiển thị không
    public boolean isCompanyLogoDisplayed() {
        try {
            wait.until(ExpectedConditions.visibilityOf(companyLogo));
            return companyLogo.isDisplayed();
        } catch (Exception e) {
            return false;
        }
    }
}
 
Dashboard Page Object
package pages;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.time.Duration;

public class DashboardPage {

    private WebDriver driver;
    private WebDriverWait wait;

    // Định nghĩa các element trên trang Dashboard
    @FindBy(css = "li.menu-item-dashboard")
    private WebElement dashboardMenu;

    @FindBy(css = ".user-menu")
    private WebElement userMenu;

    @FindBy(css = ".top_search_icon")
    private WebElement searchIcon;

    @FindBy(css = ".screen-options-btn")
    private WebElement screenOptionsButton;

    // Khởi tạo các element với PageFactory
    public DashboardPage(WebDriver driver) {
        this.driver = driver;
        this.wait = new WebDriverWait(driver, Duration.ofSeconds(15));
        PageFactory.initElements(driver, this);
    }

    // Kiểm tra xem đã đăng nhập thành công chưa
    public boolean isOnDashboardPage() {
        try {
            wait.until(ExpectedConditions.visibilityOf(dashboardMenu));
            return dashboardMenu.isDisplayed();
        } catch (Exception e) {
            return false;
        }
    }

    // Mở menu người dùng
    public DashboardPage openUserMenu() {
        wait.until(ExpectedConditions.elementToBeClickable(userMenu));
        userMenu.click();
        return this;
    }

    // Click vào biểu tượng tìm kiếm
    public SearchPage clickSearchIcon() {
        wait.until(ExpectedConditions.elementToBeClickable(searchIcon));
        searchIcon.click();
        return new SearchPage(driver);
    }
}
 
Forgot Password Page Object
package pages;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.time.Duration;

public class ForgotPasswordPage {

    private WebDriver driver;
    private WebDriverWait wait;

    @FindBy(id = "email")
    private WebElement emailInput;

    @FindBy(css = "button[type='submit']")
    private WebElement submitButton;

    @FindBy(css = ".alert-success")
    private WebElement successMessage;

    @FindBy(css = ".alert-danger")
    private WebElement errorMessage;

    @FindBy(linkText = "Back to Login")
    private WebElement backToLoginLink;

    // Khởi tạo các element với PageFactory
    public ForgotPasswordPage(WebDriver driver) {
        this.driver = driver;
        this.wait = new WebDriverWait(driver, Duration.ofSeconds(15));
        PageFactory.initElements(driver, this);
    }

    // Nhập email để khôi phục mật khẩu
    public ForgotPasswordPage enterEmail(String email) {
        wait.until(ExpectedConditions.visibilityOf(emailInput));
        emailInput.clear();
        emailInput.sendKeys(email);
        return this;
    }

    // Click vào nút Submit
    public ForgotPasswordPage clickSubmitButton() {
        wait.until(ExpectedConditions.elementToBeClickable(submitButton));
        submitButton.click();
        return this;
    }

    // Quay lại trang login
    public LoginPage clickBackToLoginLink() {
        wait.until(ExpectedConditions.elementToBeClickable(backToLoginLink));
        backToLoginLink.click();
        return new LoginPage(driver);
    }

    // Kiểm tra xem thông báo thành công có hiển thị không
    public boolean isSuccessMessageDisplayed() {
        try {
            wait.until(ExpectedConditions.visibilityOf(successMessage));
            return successMessage.isDisplayed();
        } catch (Exception e) {
            return false;
        }
    }

    // Kiểm tra xem thông báo lỗi có hiển thị không
    public boolean isErrorMessageDisplayed() {
        try {
            wait.until(ExpectedConditions.visibilityOf(errorMessage));
            return errorMessage.isDisplayed();
        } catch (Exception e) {
            return false;
        }
    }
}
 
Login Test Class
package tests;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import pages.DashboardPage;
import pages.LoginPage;
import pages.ForgotPasswordPage;

public class LoginTest {

    private WebDriver driver;
    private LoginPage loginPage;

    @BeforeMethod
    public void setUp() {
        // Khởi tạo driver
        driver = new ChromeDriver();
        driver.manage().window().maximize();
        
        // Khởi tạo trang Login
        loginPage = new LoginPage(driver);
    }

    @Test(description = "Đăng nhập thành công với thông tin đúng")
    public void testSuccessfulLogin() {
        // Thực hiện đăng nhập
        DashboardPage dashboardPage = loginPage
                .openLoginPage()
                .login("admin@example.com", "password");
        
        // Kiểm tra xem đã đăng nhập thành công chưa
        Assert.assertTrue(dashboardPage.isOnDashboardPage(), "Đăng nhập không thành công!");
    }

    @Test(description = "Đăng nhập thất bại với email không hợp lệ")
    public void testLoginWithInvalidEmail() {
        // Thực hiện đăng nhập với email không hợp lệ
        loginPage
                .openLoginPage()
                .enterEmail("invalid@example.com")
                .enterPassword("password")
                .clickLoginButton();
        
        // Kiểm tra thông báo lỗi
        Assert.assertTrue(loginPage.isErrorMessageDisplayed(), "Thông báo lỗi không hiển thị!");
    }

    @Test(description = "Đăng nhập thất bại với password không đúng")
    public void testLoginWithInvalidPassword() {
        // Thực hiện đăng nhập với password không đúng
        loginPage
                .openLoginPage()
                .enterEmail("admin@example.com")
                .enterPassword("wrongpassword")
                .clickLoginButton();
        
        // Kiểm tra thông báo lỗi
        Assert.assertTrue(loginPage.isErrorMessageDisplayed(), "Thông báo lỗi không hiển thị!");
    }

    @Test(description = "Kiểm tra chức năng quên mật khẩu")
    public void testForgotPassword() {
        // Mở trang quên mật khẩu
        ForgotPasswordPage forgotPasswordPage = loginPage
                .openLoginPage()
                .clickForgotPasswordLink();
        
        // Nhập email để khôi phục mật khẩu
        forgotPasswordPage
                .enterEmail("admin@example.com")
                .clickSubmitButton();
        
        // Kiểm tra thông báo thành công
        Assert.assertTrue(forgotPasswordPage.isSuccessMessageDisplayed(), "Không hiển thị thông báo gửi email thành công!");
    }

    @AfterMethod
    public void tearDown() {
        // Đóng browser sau khi test hoàn thành
        if (driver != null) {
            driver.quit();
        }
    }
}
 
Maven pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.anhtester</groupId>
    <artifactId>crm-automation</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <selenium.version>4.17.0</selenium.version>
        <testng.version>7.8.0</testng.version>
        <webdrivermanager.version>5.6.3</webdrivermanager.version>
    </properties>

    <dependencies>
        <!-- Selenium Java -->
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>${selenium.version}</version>
        </dependency>

        <!-- TestNG -->
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>${testng.version}</version>
            <scope>test</scope>
        </dependency>

        <!-- WebDriverManager -->
        <dependency>
            <groupId>io.github.bonigarcia</groupId>
            <artifactId>webdrivermanager</artifactId>
            <version>${webdrivermanager.version}</version>
        </dependency>

        <!-- SLF4J API -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>2.0.9</version>
        </dependency>

        <!-- SLF4J Binding -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>2.0.9</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.target}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.2.3</version>
                <configuration>
                    <suiteXmlFiles>
                        <suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
                    </suiteXmlFiles>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
 
TestNG configuration file
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="CRM Test Suite">
    <test name="Login Tests">
        <classes>
            <class name="tests.LoginTest"/>
        </classes>
    </test>
</suite>
 
Search Page Object
package pages;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.time.Duration;

public class SearchPage {

    private WebDriver driver;
    private WebDriverWait wait;

    @FindBy(css = "input.search")
    private WebElement searchInput;

    @FindBy(css = ".search-results")
    private WebElement searchResults;

    // Khởi tạo các element với PageFactory
    public SearchPage(WebDriver driver) {
        this.driver = driver;
        this.wait = new WebDriverWait(driver, Duration.ofSeconds(15));
        PageFactory.initElements(driver, this);
    }

    // Nhập từ khóa tìm kiếm
    public SearchPage enterSearchKeyword(String keyword) {
        wait.until(ExpectedConditions.visibilityOf(searchInput));
        searchInput.clear();
        searchInput.sendKeys(keyword);
        return this;
    }

    // Kiểm tra xem kết quả tìm kiếm có hiển thị không
    public boolean isSearchResultsDisplayed() {
        try {
            wait.until(ExpectedConditions.visibilityOf(searchResults));
            return searchResults.isDisplayed();
        } catch (Exception e) {
            return false;
        }
    }
}
 
Base Page Object
package pages;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.time.Duration;

public class BasePage {

    protected WebDriver driver;
    protected WebDriverWait wait;

    public BasePage(WebDriver driver) {
        this.driver = driver;
        this.wait = new WebDriverWait(driver, Duration.ofSeconds(15));
    }

    // Các phương thức chung cho tất cả các trang

    // Đợi cho đến khi element hiển thị
    protected void waitForElementVisible(WebElement element) {
        wait.until(ExpectedConditions.visibilityOf(element));
    }

    // Đợi cho đến khi element có thể click được
    protected void waitForElementClickable(WebElement element) {
        wait.until(ExpectedConditions.elementToBeClickable(element));
    }

    // Nhập text vào element
    protected void sendKeysToElement(WebElement element, String text) {
        waitForElementVisible(element);
        element.clear();
        element.sendKeys(text);
    }

    // Click vào element
    protected void clickElement(WebElement element) {
        waitForElementClickable(element);
        element.click();
    }

    // Lấy text của element
    protected String getElementText(WebElement element) {
        waitForElementVisible(element);
        return element.getText();
    }

    // Kiểm tra xem element có hiển thị hay không
    protected boolean isElementDisplayed(WebElement element) {
        try {
            waitForElementVisible(element);
            return element.isDisplayed();
        } catch (Exception e) {
            return false;
        }
    }

    // Lấy title của trang hiện tại
    public String getPageTitle() {
        return driver.getTitle();
    }

    // Lấy URL hiện tại
    public String getCurrentUrl() {
        return driver.getCurrentUrl();
    }
}


Tôi đã tạo một cấu trúc Page Object Model (POM) đầy đủ cho trang đăng nhập của hệ thống CRM. Dưới đây là giải thích về các file đã được tạo:

  1. LoginPage.java:
    • Chứa tất cả các element của trang đăng nhập
    • Các phương thức để thao tác với trang đăng nhập
    • Sử dụng cơ chế page chaining để tạo fluent API
  2. DashboardPage.java:
    • Trang đích sau khi đăng nhập thành công
    • Chứa các phương thức kiểm tra xem đã đăng nhập thành công chưa
  3. ForgotPasswordPage.java:
    • Xử lý tính năng quên mật khẩu
    • Các element và phương thức liên quan đến chức năng này
  4. SearchPage.java:
    • Xử lý tính năng tìm kiếm trên hệ thống
  5. BasePage.java:
    • Lớp cơ sở chứa các phương thức dùng chung
    • Phương thức wait, click, sendKeys... được đóng gói lại
  6. LoginTest.java:
    • Test class sử dụng TestNG
    • Các test case cho chức năng đăng nhập
  7. pom.xml:
    • Cấu hình Maven project
    • Khai báo các dependency cần thiết
  8. testng.xml:
    • File cấu hình để chạy test bằng TestNG


Để sử dụng code này, bạn cần:

  1. Tạo một Maven project mới
  2. Đặt tất cả các file trong đúng package
  3. Sửa lại thông tin đăng nhập (email, password) phù hợp với tài khoản của bạn
  4. Chạy test bằng cách thực thi file testng.xml

Cấu trúc dự án sẽ như sau:

src/
  ├── main/
  │   └── java/
  │       └── pages/
  │           ├── BasePage.java
  │           ├── LoginPage.java
  │           ├── DashboardPage.java
  │           ├── ForgotPasswordPage.java
  │           └── SearchPage.java
  └── test/
      ├── java/
      │   └── tests/
      │       └── LoginTest.java
      └── resources/
          └── testng.xml


🤩 Anh Tester chỉ biết lặng lẽ copy code và dùng thôi chứ không biết nói gì luôn, tao lạy mày AI à @@


Cách khác, bạn có thể upload hình ảnh về trang web cần thiết kế code test automation, sau đó mô tả cho nó là generate code cho trang như hình đính kèm, dùng thư viện cụ thể gì đó. Chờ xem kết quả bất ngờ.


Ví dụ dùng Claude và upload một tấm hình trang web cụ thể:


✳️"Bạn giúp tôi generate test cases và Page Object Model cho trang web tôi đính kèm trong hình với Selenium Java TestNG Framework"

⭐️Kết quả AI trả lời như sau:

Tôi sẽ giúp bạn tạo test cases và thiết kế Page Object Model (POM) cho trang web quản lý khách hàng này sử dụng Selenium Java với TestNG Framework.

Page Object Model cho Trang Quản lý Khách hàng
// File: src/main/java/pages/BasePage.java
package pages;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.time.Duration;
import java.util.List;

public class BasePage {
    protected WebDriver driver;
    protected WebDriverWait wait;

    public BasePage(WebDriver driver) {
        this.driver = driver;
        this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));
    }

    protected WebElement waitForElementToBeVisible(By locator) {
        return wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
    }

    protected WebElement waitForElementToBeClickable(By locator) {
        return wait.until(ExpectedConditions.elementToBeClickable(locator));
    }

    protected void click(By locator) {
        waitForElementToBeClickable(locator).click();
    }

    protected void sendKeys(By locator, String text) {
        waitForElementToBeVisible(locator).sendKeys(text);
    }

    protected String getText(By locator) {
        return waitForElementToBeVisible(locator).getText();
    }

    protected List<WebElement> findElements(By locator) {
        return driver.findElements(locator);
    }

    protected boolean isElementDisplayed(By locator) {
        try {
            return driver.findElement(locator).isDisplayed();
        } catch (Exception e) {
            return false;
        }
    }
}

// File: src/main/java/pages/LoginPage.java
package pages;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;

public class LoginPage extends BasePage {
    // Locators
    private final By usernameInput = By.id("username"); // Adjust selector as needed
    private final By passwordInput = By.id("password"); // Adjust selector as needed
    private final By loginButton = By.id("login-button"); // Adjust selector as needed

    public LoginPage(WebDriver driver) {
        super(driver);
    }

    public void enterUsername(String username) {
        sendKeys(usernameInput, username);
    }

    public void enterPassword(String password) {
        sendKeys(passwordInput, password);
    }

    public CustomerPage clickLoginButton() {
        click(loginButton);
        return new CustomerPage(driver);
    }

    public CustomerPage login(String username, String password) {
        enterUsername(username);
        enterPassword(password);
        return clickLoginButton();
    }
}

// File: src/main/java/pages/CustomerPage.java
package pages;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

import java.util.ArrayList;
import java.util.List;

public class CustomerPage extends BasePage {
    // Locators
    private final By newCustomerButton = By.xpath("//button[contains(text(),'New Customer')]");
    private final By importCustomersButton = By.xpath("//button[contains(text(),'Import Customers')]");
    private final By contactsButton = By.xpath("//button[contains(text(),'Contacts')]");
    private final By searchInput = By.xpath("//input[@placeholder='Search...']");
    private final By totalCustomersCount = By.xpath("//div[contains(text(),'Total Customers')]/preceding-sibling::div");
    private final By activeCustomersCount = By.xpath("//div[contains(text(),'Active Customers')]/preceding-sibling::div");
    private final By inactiveCustomersCount = By.xpath("//div[contains(text(),'Inactive Customers')]/preceding-sibling::div");
    private final By customerRows = By.xpath("//table/tbody/tr");
    private final By exportButton = By.xpath("//button[contains(text(),'Export')]");
    private final By bulkActionsButton = By.xpath("//button[contains(text(),'Bulk Actions')]");
    private final By refreshButton = By.xpath("//button[@title='Refresh']");
    private final By searchTableInput = By.xpath("//input[@placeholder='Search...' and not(ancestor::div[@class='search-box'])]");

    public CustomerPage(WebDriver driver) {
        super(driver);
    }

    public boolean isPageLoaded() {
        return isElementDisplayed(newCustomerButton) && isElementDisplayed(totalCustomersCount);
    }

    public void clickNewCustomerButton() {
        click(newCustomerButton);
    }

    public void clickImportCustomersButton() {
        click(importCustomersButton);
    }

    public void clickContactsButton() {
        click(contactsButton);
    }

    public void searchCustomers(String searchText) {
        sendKeys(searchInput, searchText);
    }

    public void searchInTable(String searchText) {
        sendKeys(searchTableInput, searchText);
    }

    public String getTotalCustomersCount() {
        return getText(totalCustomersCount);
    }

    public String getActiveCustomersCount() {
        return getText(activeCustomersCount);
    }

    public String getInactiveCustomersCount() {
        return getText(inactiveCustomersCount);
    }

    public void clickExportButton() {
        click(exportButton);
    }

    public void clickBulkActionsButton() {
        click(bulkActionsButton);
    }

    public void clickRefreshButton() {
        click(refreshButton);
    }

    public int getNumberOfCustomerRows() {
        return findElements(customerRows).size();
    }

    public List<CustomerData> getCustomersData() {
        List<CustomerData> customers = new ArrayList<>();
        List<WebElement> rows = findElements(customerRows);
        
        for (WebElement row : rows) {
            String id = row.findElement(By.xpath("./td[2]")).getText();
            String company = row.findElement(By.xpath("./td[3]")).getText();
            boolean isActive = row.findElement(By.xpath(".//input[@type='checkbox']")).isSelected();
            String dateCreated = row.findElement(By.xpath("./td[last()]")).getText();
            
            customers.add(new CustomerData(id, company, isActive, dateCreated));
        }
        
        return customers;
    }

    public void selectCustomerByRow(int rowIndex) {
        By checkbox = By.xpath("(//table/tbody/tr)[" + rowIndex + "]//input[@type='checkbox']");
        click(checkbox);
    }

    public void toggleCustomerActiveStatus(int rowIndex) {
        By toggleSwitch = By.xpath("(//table/tbody/tr)[" + rowIndex + "]//div[contains(@class, 'toggle-switch')]");
        click(toggleSwitch);
    }

    // Helper class to store customer data
    public static class CustomerData {
        private String id;
        private String company;
        private boolean isActive;
        private String dateCreated;

        public CustomerData(String id, String company, boolean isActive, String dateCreated) {
            this.id = id;
            this.company = company;
            this.isActive = isActive;
            this.dateCreated = dateCreated;
        }

        public String getId() {
            return id;
        }

        public String getCompany() {
            return company;
        }

        public boolean isActive() {
            return isActive;
        }

        public String getDateCreated() {
            return dateCreated;
        }
    }
}

// File: src/main/java/pages/NewCustomerPage.java
package pages;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;

public class NewCustomerPage extends BasePage {
    // Locators (adjust these as needed based on the actual form)
    private final By companyNameInput = By.id("company-name");
    private final By contactNameInput = By.id("contact-name");
    private final By emailInput = By.id("email");
    private final By phoneInput = By.id("phone");
    private final By saveButton = By.xpath("//button[contains(text(),'Save')]");
    private final By cancelButton = By.xpath("//button[contains(text(),'Cancel')]");

    public NewCustomerPage(WebDriver driver) {
        super(driver);
    }

    public boolean isPageLoaded() {
        return isElementDisplayed(companyNameInput) && isElementDisplayed(saveButton);
    }

    public void enterCompanyName(String companyName) {
        sendKeys(companyNameInput, companyName);
    }

    public void enterContactName(String contactName) {
        sendKeys(contactNameInput, contactName);
    }

    public void enterEmail(String email) {
        sendKeys(emailInput, email);
    }

    public void enterPhone(String phone) {
        sendKeys(phoneInput, phone);
    }

    public CustomerPage clickSaveButton() {
        click(saveButton);
        return new CustomerPage(driver);
    }

    public CustomerPage clickCancelButton() {
        click(cancelButton);
        return new CustomerPage(driver);
    }

    public CustomerPage createCustomer(String companyName, String contactName, String email, String phone) {
        enterCompanyName(companyName);
        enterContactName(contactName);
        enterEmail(email);
        enterPhone(phone);
        return clickSaveButton();
    }
}
 
Test Cases cho Trang Quản lý Khách hàng
// File: src/test/java/tests/BaseTest.java
package tests;

import io.github.bonigarcia.wdm.WebDriverManager;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import pages.LoginPage;

import java.time.Duration;

public class BaseTest {
    protected WebDriver driver;
    protected LoginPage loginPage;
    protected final String BASE_URL = "https://anhtester.com"; // Điều chỉnh URL tới hệ thống của bạn

    @BeforeMethod
    public void setUp() {
        WebDriverManager.chromedriver().setup();
        ChromeOptions options = new ChromeOptions();
        options.addArguments("--start-maximized");
        options.addArguments("--disable-notifications");
        
        driver = new ChromeDriver(options);
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
        driver.get(BASE_URL);
        
        loginPage = new LoginPage(driver);
    }

    @AfterMethod
    public void tearDown() {
        if (driver != null) {
            driver.quit();
        }
    }
}

// File: src/test/java/tests/CustomerPageTest.java
package tests;

import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import pages.CustomerPage;

import java.util.List;

public class CustomerPageTest extends BaseTest {
    private CustomerPage customerPage;

    @BeforeMethod
    public void navigateToCustomerPage() {
        // Đăng nhập và điều hướng tới trang khách hàng
        customerPage = loginPage.login("admin", "password");
        Assert.assertTrue(customerPage.isPageLoaded(), "Customer page is not loaded");
    }

    @Test(description = "Verify customer summary statistics")
    public void testCustomerSummaryStatistics() {
        // Kiểm tra thông tin tổng quan về khách hàng
        String totalCustomers = customerPage.getTotalCustomersCount();
        String activeCustomers = customerPage.getActiveCustomersCount();
        String inactiveCustomers = customerPage.getInactiveCustomersCount();
        
        Assert.assertEquals(totalCustomers, "549", "Total customers count is incorrect");
        Assert.assertEquals(activeCustomers, "548", "Active customers count is incorrect");
        Assert.assertEquals(inactiveCustomers, "1", "Inactive customers count is incorrect");
    }
    
    @Test(description = "Verify customer table displays correct number of rows")
    public void testCustomerTableRows() {
        // Kiểm tra số lượng hàng trong bảng khách hàng
        int rowCount = customerPage.getNumberOfCustomerRows();
        Assert.assertTrue(rowCount > 0, "Customer table should have at least one row");
    }
    
    @Test(description = "Test search functionality in customer table")
    public void testSearchFunctionality() {
        // Tìm kiếm khách hàng với ID '123abc'
        customerPage.searchInTable("123abc");
        
        // Kiểm tra kết quả tìm kiếm
        List<CustomerPage.CustomerData> customers = customerPage.getCustomersData();
        Assert.assertTrue(customers.size() > 0, "Search should return at least one result");
        
        // Kiểm tra mọi kết quả đều chứa chuỗi tìm kiếm
        for (CustomerPage.CustomerData customer : customers) {
            Assert.assertTrue(
                customer.getId().contains("123abc") || 
                customer.getCompany().contains("123abc"),
                "Search result should contain the search string"
            );
        }
    }
    
    @Test(description = "Test customer active toggle functionality")
    public void testToggleCustomerActiveStatus() {
        // Lấy trạng thái ban đầu của khách hàng đầu tiên
        List<CustomerPage.CustomerData> customersBefore = customerPage.getCustomersData();
        boolean initialStatus = customersBefore.get(0).isActive();
        
        // Chuyển đổi trạng thái
        customerPage.toggleCustomerActiveStatus(1);
        
        // Làm mới trang và lấy trạng thái mới
        customerPage.clickRefreshButton();
        List<CustomerPage.CustomerData> customersAfter = customerPage.getCustomersData();
        boolean newStatus = customersAfter.get(0).isActive();
        
        // Kiểm tra trạng thái đã thay đổi
        Assert.assertNotEquals(initialStatus, newStatus, "Customer active status should be toggled");
    }
    
    @Test(description = "Verify date created format in customer table")
    public void testDateCreatedFormat() {
        // Lấy dữ liệu khách hàng
        List<CustomerPage.CustomerData> customers = customerPage.getCustomersData();
        
        // Kiểm tra định dạng ngày tạo (dd-mm-yyyy HH:MM:SS)
        String dateRegex = "\\d{2}-\\d{2}-\\d{4} \\d{2}:\\d{2}:\\d{2}";
        for (CustomerPage.CustomerData customer : customers) {
            Assert.assertTrue(
                customer.getDateCreated().matches(dateRegex),
                "Date created format should match dd-mm-yyyy HH:MM:SS"
            );
        }
    }
    
    @Test(description = "Test bulk selection of customers")
    public void testBulkSelection() {
        // Chọn một vài khách hàng
        customerPage.selectCustomerByRow(1);
        customerPage.selectCustomerByRow(2);
        
        // Click vào bulk actions
        customerPage.clickBulkActionsButton();
        
        // Thêm verification cho bulk actions menu nếu có thể xác định được element
        // Assert.assertTrue(customerPage.isBulkActionsMenuDisplayed(), "Bulk actions menu should be displayed");
    }
}

// File: src/test/java/tests/NewCustomerTest.java
package tests;

import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import pages.CustomerPage;
import pages.NewCustomerPage;

import java.util.UUID;

public class NewCustomerTest extends BaseTest {
    private CustomerPage customerPage;
    private NewCustomerPage newCustomerPage;

    @BeforeMethod
    public void navigateToNewCustomerPage() {
        // Đăng nhập và điều hướng tới trang khách hàng
        customerPage = loginPage.login("admin", "password");
        Assert.assertTrue(customerPage.isPageLoaded(), "Customer page is not loaded");
        
        // Click button New Customer
        customerPage.clickNewCustomerButton();
        newCustomerPage = new NewCustomerPage(driver);
        Assert.assertTrue(newCustomerPage.isPageLoaded(), "New customer page is not loaded");
    }

    @Test(description = "Create a new customer with valid data")
    public void testCreateNewCustomer() {
        // Tạo dữ liệu ngẫu nhiên
        String companyName = "Test Company " + UUID.randomUUID().toString().substring(0, 8);
        String contactName = "Test Contact";
        String email = "test" + UUID.randomUUID().toString().substring(0, 8) + "@example.com";
        String phone = "0123456789";
        
        // Tạo khách hàng mới
        CustomerPage resultPage = newCustomerPage.createCustomer(companyName, contactName, email, phone);
        
        // Xác nhận đã quay về trang danh sách khách hàng
        Assert.assertTrue(resultPage.isPageLoaded(), "Should return to customer page after creation");
        
        // Tìm kiếm khách hàng vừa tạo để xác nhận
        resultPage.searchInTable(companyName);
        
        // Lấy danh sách kết quả và kiểm tra
        Assert.assertTrue(
            resultPage.getCustomersData().stream()
                .anyMatch(customer -> customer.getCompany().equals(companyName)),
            "Newly created customer should be found in the table"
        );
    }
    
    @Test(description = "Cancel new customer creation")
    public void testCancelCustomerCreation() {
        // Nhập một số thông tin
        newCustomerPage.enterCompanyName("Canceled Company");
        
        // Hủy việc tạo khách hàng
        CustomerPage resultPage = newCustomerPage.clickCancelButton();
        
        // Xác nhận đã quay về trang danh sách khách hàng
        Assert.assertTrue(resultPage.isPageLoaded(), "Should return to customer page after cancellation");
        
        // Tìm kiếm khách hàng đã hủy tạo
        resultPage.searchInTable("Canceled Company");
        
        // Lấy danh sách kết quả và kiểm tra không có khách hàng này
        Assert.assertEquals(
            resultPage.getNumberOfCustomerRows(), 0,
            "Canceled customer should not be found in the table"
        );
    }
}

// File: src/test/java/tests/testng.xml
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Customer Management Suite">
    <test name="Customer Management Tests">
        <classes>
            <class name="tests.CustomerPageTest"/>
            <class name="tests.NewCustomerTest"/>
        </classes>
    </test>
</suite>

Dựa vào hình ảnh trang web bạn đã cung cấp, tôi đã thiết kế một bộ Page Object Model (POM) và test cases sử dụng Selenium Java với TestNG Framework. Hãy xem lại cấu trúc và giải thích:


Cấu trúc Page Object Model:

  1. BasePage: Lớp cơ sở chứa các phương thức thao tác chung như click, sendKeys, wait...
  2. LoginPage: Trang đăng nhập để vào hệ thống
  3. CustomerPage: Trang quản lý khách hàng chính với các phương thức:
    • Lấy thông tin tổng quan (tổng số, số lượng active/inactive)
    • Tìm kiếm khách hàng
    • Chọn và thay đổi trạng thái khách hàng
    • Lấy danh sách thông tin khách hàng
  4. NewCustomerPage: Trang tạo khách hàng mới với các trường thông tin cần thiết


Test Cases:

  1. BaseTest: Thiết lập và dọn dẹp môi trường test
  2. CustomerPageTest: Kiểm tra các chức năng của trang khách hàng:
    • Xác minh số liệu thống kê tổng quan
    • Kiểm tra hiển thị bảng dữ liệu
    • Kiểm tra chức năng tìm kiếm
    • Kiểm tra chức năng chuyển đổi trạng thái active/inactive
    • Kiểm tra định dạng ngày tháng
    • Kiểm tra chức năng chọn nhiều (bulk selection)
  3. NewCustomerTest: Kiểm tra chức năng tạo khách hàng mới:
    • Tạo khách hàng mới thành công
    • Hủy quá trình tạo khách hàng


Lưu ý khi triển khai:

  1. Cần điều chỉnh các selector (locator) cho phù hợp với cấu trúc HTML thực tế của trang web.
  2. URL trong BaseTest cần được thay đổi thành URL thực tế của hệ thống.
  3. Thông tin đăng nhập cần được cập nhật theo tài khoản thực tế.
  4. Một số test case có thể cần điều chỉnh dựa trên hành vi thực tế của ứng dụng, đặc biệt là trong việc xác nhận kết quả sau khi thực hiện các thao tác.
  5. Bạn nên bổ sung thêm log và reporting (như ExtentReports) để giúp phân tích kết quả test dễ dàng hơn.

Bạn có thể mở rộng test framework này bằng cách thêm các test case khác như:

  • Kiểm tra nhập liệu không hợp lệ
  • Kiểm tra phân trang
  • Kiểm tra chức năng import/export
  • Kiểm tra các permission khác nhau


🤩 Nếu các bạn đang có kinh nghiệm code thì việc thiết kế sẵn từ AI như này chỉ việc copy dán vào và edit chút là xong. Ngoài ra các bạn có thể tiếp tục khai phá con AI cho những câu hỏi tiếp tục về chủ đề đang hỏi chi tiết hơn.

Ví dụ kêu nó chuyển từ đối tượng @FindBy sang By hoặc ngược lại. Hoặc kêu nó thiết kế code cụ thể thêm các field cụ thể mà chúng ta điền vào luôn. Vì dù sao thì nó cũng chỉ giúp mình hỗ trợ mình chứ không thể hiểu hết Flow Business liền được, cần cung cấp thông tin cho nó từ từ và chi tiết hơn để có kết quả sát với mong muốn.

Các bạn xem video mình làm mẫu chi tiết nhé !!
  • Anh Tester

    Đường dẫu khó chân vẫn cần bước đi
    Đời dẫu khổ tâm vẫn cần nghĩ thấu