NỘI DUNG BÀI HỌC
✅Công dụng của Annotations trong TestNG Framework
✅Các Annotations chính trong TestNG Framework
✅ Khai báo Annotations trên một Class (không có kế thừa)
✅ Khai báo Annotation khi có kế thừa (Extends)
✅Công dụng của Annotations trong TestNG Framework
Trong TestNG Framework, annotations được sử dụng để xác định phương thức nào sẽ được chạy trong quá trình kiểm thử và quy định cách thức chạy của chúng. Các annotation này giúp tổ chức, quản lý và điều phối quá trình kiểm thử một cách dễ dàng.
Hiện tại TestNG cung cấp 10 Annotations ở dạng Before và After và 1 Annotation dạng Test để điều phối sắp xếp việc thực thi test cases.
- @BeforeSuite/@AfterSuite
- @BeforeTest/@AfterTest
- @BeforeGroups/@AfterGroups
- @BeforeClass/@AfterClass
- @BeforeMethod/@AfterMethod
- @Test
Xem thêm: https://testng.org/#_annotations
Annotation giúp thêm thông tin vào một đối tượng. Nó có thể được dùng cho class, method, và parameters. TestNG cung cấp rất nhiều loại annotation cho các mục đích khác nhau, trong đó quan trọng có các annotation phục vụ cho mục đích xử lý trước và sau phương thức Test (trước khi chạy test và sau khi chạy test xong).
✳️Vì sao cần xử lý trước và sau phương thức Test?
Trong quá trình kiểm thử tự động với TestNG, việc xử lý trước và sau mỗi phương thức test (@Test
) là rất quan trọng để đảm bảo kiểm thử diễn ra chính xác, độc lập và không bị ảnh hưởng bởi trạng thái của các test khác.
Dưới đây là một số lý do chính:
1. Cần thiết lập môi trường trước khi thực hiện test
- Để đảm bảo mỗi test case được thực thi trong một môi trường đúng và sạch, chúng ta cần chuẩn bị dữ liệu hoặc cấu hình trước khi test chạy.
- Ví dụ:
- Mở trình duyệt và điều hướng đến trang web cần kiểm thử.
- Khởi tạo kết nối với cơ sở dữ liệu hoặc API.
- Đăng nhập tài khoản trước khi chạy test nếu cần.
Ví dụ:
@BeforeMethod
public void setup() {
System.out.println("Khởi tạo trình duyệt và đăng nhập vào hệ thống");
}
2. Cần xóa trạng thái sau khi thực hiện test
- Sau khi test chạy xong, cần dọn dẹp để tránh ảnh hưởng đến các test khác.
- Ví dụ:
- Xóa dữ liệu test đã được tạo ra.
- Đăng xuất tài khoản sau khi test hoàn thành.
- Đóng trình duyệt để tránh lỗi khi chạy nhiều test liên tiếp.
Ví dụ:
@AfterMethod
public void tearDown() {
System.out.println("Đóng trình duyệt và xóa dữ liệu test");
}
3. Thực hiện các hành động cần thiết nhưng không liên quan đến phương thức test
- Một số thao tác không ảnh hưởng trực tiếp đến logic test nhưng vẫn rất quan trọng, ví dụ:
- Chụp ảnh màn hình (screenshot) khi test thất bại để phân tích lỗi.
- Ghi log hoặc lưu trữ kết quả test để kiểm tra sau này.
- Xóa session hoặc cache để tránh ảnh hưởng đến các test khác.
Ví dụ:
@AfterMethod
public void takeScreenshotIfTestFails(ITestResult result) {
if (!result.isSuccess()) {
System.out.println("Chụp ảnh màn hình do test thất bại");
}
}
✅Các Annotations chính trong TestNG Framework
1. @Test
- Ý nghĩa: Đánh dấu một phương thức là một test case.
- Khi nào chạy: Khi chạy bộ kiểm thử (test suite), các phương thức có
@Test
sẽ được thực thi. - Ví dụ:
@Test public void testLogin() { System.out.println("Thực hiện kiểm thử đăng nhập"); }
2. @BeforeSuite
- Ý nghĩa: Phương thức này chạy trước tất cả các test trong test suite.
- Khi nào chạy: Trước khi bắt đầu chạy bất kỳ test case nào.
- Ví dụ:
@BeforeSuite public void beforeSuite() { System.out.println("Chạy trước toàn bộ suite"); }
3. @AfterSuite
- Ý nghĩa: Phương thức này chạy sau tất cả các test trong test suite.
- Khi nào chạy: Sau khi tất cả test case đã hoàn thành.
- Ví dụ:
@AfterSuite public void afterSuite() { System.out.println("Chạy sau toàn bộ suite"); }
4. @BeforeTest
- Ý nghĩa: Chạy trước khi thực hiện bất kỳ @Test nào thuộc cùng một
<test>
trong XML. - Khi nào chạy: Trước khi bất kỳ phương thức
@Test
nào được thực thi trong file XML đó. - Ví dụ:
@BeforeTest public void beforeTest() { System.out.println("Chạy trước tất cả các test trong một thẻ <test>"); }
5. @AfterTest
- Ý nghĩa: Chạy sau khi tất cả các @Test trong cùng một
<test>
đã hoàn thành. - Khi nào chạy: Sau khi tất cả các phương thức
@Test
trong<test>
của XML đã chạy xong. - Ví dụ:
@AfterTest public void afterTest() { System.out.println("Chạy sau tất cả các test trong một thẻ <test>"); }
6. @BeforeGroups
- Ý nghĩa: Chạy trước test đầu tiên trong một nhóm (group) được gọi.
- Khi nào chạy: Trước khi bất kỳ test nào thuộc một nhóm nhất định được thực thi.
- Ví dụ:
@BeforeGroups("login") public void beforeGroup() { System.out.println("Chạy trước nhóm test login"); }
7. @AfterGroups
- Ý nghĩa: Chạy sau test cuối cùng trong một nhóm (group) được gọi.
- Khi nào chạy: Ngay sau khi test cuối cùng trong nhóm đó hoàn tất.
- Ví dụ:
@AfterGroups("login") public void afterGroup() { System.out.println("Chạy sau nhóm test login"); }
8. @BeforeClass
- Ý nghĩa: Chạy trước khi thực hiện test đầu tiên trong class hiện tại.
- Khi nào chạy: Sau
@BeforeTest
, nhưng trước bất kỳ@Test
nào trong class đó. - Ví dụ:
@BeforeClass public void beforeClass() { System.out.println("Chạy trước tất cả các test trong class này"); }
9. @AfterClass
- Ý nghĩa: Chạy sau khi tất cả test trong class hiện tại đã chạy xong.
- Khi nào chạy: Trước
@AfterTest
, nhưng sau tất cả@Test
trong class đó. - Ví dụ:
@AfterClass public void afterClass() { System.out.println("Chạy sau tất cả các test trong class này"); }
10. @BeforeMethod
- Ý nghĩa: Chạy trước mỗi test case (
@Test
). - Khi nào chạy: Trước mỗi phương thức
@Test
trong class. - Ví dụ:
@BeforeMethod public void beforeMethod() { System.out.println("Chạy trước mỗi phương thức test"); }
11. @AfterMethod
- Ý nghĩa: Chạy sau mỗi test case (
@Test
). - Khi nào chạy: Ngay sau mỗi phương thức
@Test
trong class. - Ví dụ:
@AfterMethod public void afterMethod() { System.out.println("Chạy sau mỗi phương thức test"); }
Tóm tắt thứ tự thực thi của các annotation trong TestNG
Giả sử chúng ta có một class chứa nhiều test case:
- @BeforeSuite
- @BeforeTest
- @BeforeClass
- @BeforeMethod
- @Test
- @AfterMethod
- @BeforeMethod
- @Test
- @AfterMethod
- @AfterClass
- @AfterTest
- @AfterSuite
Lưu ý:
- Các annotation giúp kiểm soát quá trình chạy test và sắp xếp chúng theo trình tự hợp lý.
- @BeforeMethod / @AfterMethod là những annotation được dùng nhiều nhất để thiết lập và dọn dẹp sau mỗi test case.
- @BeforeClass / @AfterClass hữu ích khi cần setup toàn bộ môi trường cho một class test.
- @BeforeSuite / @AfterSuite được dùng để cấu hình cấp cao hơn cho toàn bộ test suite.
✅ Khai báo Annotations trên một Class (không có kế thừa)
📌 Thứ tự chạy khi bắt đầu (Setup)
✅ Mở từ cấp lớn nhất đến nhỏ nhất:
1️⃣ @BeforeSuite
→ (Thiết lập chung cho toàn bộ suite)
2️⃣ @BeforeTest
→ (Thiết lập chung cho mỗi <test>
trong file XML)
3️⃣ @BeforeGroups
→ (Thiết lập chung cho các nhóm test nếu có)
4️⃣ @BeforeClass
→ (Thiết lập trước khi chạy các test trong class)
5️⃣ @BeforeMethod
→ (Thiết lập trước mỗi test case - chạy nhiều lần trước từng @Test
)
6️⃣ @Test
→ (Chạy từng test case)
📌 Thứ tự chạy khi kết thúc (Teardown)
❌ Đóng theo thứ tự ngược lại (từ nhỏ đến lớn):
1️⃣ @AfterMethod
→ (Dọn dẹp sau từng test case - chạy nhiều lần sau từng @Test
)
2️⃣ @AfterClass
→ (Dọn dẹp sau khi tất cả các test trong class đã chạy xong)
3️⃣ @AfterGroups
→ (Dọn dẹp sau khi nhóm test chạy xong nếu có)
4️⃣ @AfterTest
→ (Dọn dẹp sau khi tất cả các test trong <test>
của XML đã hoàn thành)
5️⃣ @AfterSuite
→ (Dọn dẹp sau khi toàn bộ test suite kết thúc)
Thứ tự chạy của chúng sẽ được thể hiện qua ví dụ sau:
public class DemoAnnotation {
@BeforeSuite
public void beforeSuite() {
System.out.println("Before Suite");
}
@AfterSuite
public void afterSuite() {
System.out.println("After Suite");
}
@BeforeTest
public void beforeTest() {
System.out.println("Before Test");
}
@AfterTest
public void afterTest() {
System.out.println("After Test");
}
@BeforeClass
public void beforeClass() {
System.out.println("Before Class");
}
@AfterClass
public void afterClass() {
System.out.println("After Class");
}
@BeforeGroups(groups = { "testOne" })
public void beforeGroupOne() {
System.out.println("Before Group testOne");
}
@AfterGroups(groups = { "testOne" })
public void afterGroupOne() {
System.out.println("After Group testOne");
}
@BeforeGroups(groups = { "testTwo" })
public void beforeGroupTwo() {
System.out.println("Before Group testTwo");
}
@AfterGroups(groups = { "testTwo" })
public void afterGroupTwo() {
System.out.println("After Group testTwo");
}
@BeforeMethod
public void beforeMethod() {
System.out.println("Before Method");
}
@AfterMethod
public void afterMethod() {
System.out.println("After Method");
}
@Test(groups = { "testOne" })
public void testOneMethod() {
System.out.println("Test method 1");
}
@Test(groups = { "testTwo" })
public void testTwoMethod() {
System.out.println("Test method 2");
}
}
Và ta cần thêm một config cho file testng.xml
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite" verbose="1">
<test name="First Test">
<classes>
<class name="com.anhtester.Bai10_Annotations.DemoAnnotation"></class>
</classes>
</test>
</suite>
Và đây là kết quả:
Các Groups sẽ có hiệu lực khi chạy nó tại XML file và có gọi tag <groups>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite" verbose="1">
<groups>
<run>
<include name="testOne"/>
<!-- include thêm các group khác -->
</run>
</groups>
<test name="Test">
<classes>
<class name="com.anhtester.Bai10_Annotations.DemoAnnotation"></class>
</classes>
</test>
</suite>
Thứ tự chạy như sau:
Suite > Test > Group > Class > Method
✔ Khi kết thúc:
Method > Class > Group > Test > Suite
✅ Khai báo Annotation khi có kế thừa (Extends)
Ở phía trên, chúng ta đã xem về cách sử dụng annation trên 1 class, chúng ta sẽ băn khoăn là thế nhưng chúng ta viết theo dạng POM thì có cả BaseTest, không biết thứ tự run annotation sẽ như thế nào?
Hãy xem ví dụ dưới đây:
Ta có class BaseTest:
public class BaseTest {
@BeforeClass
public void beforeBaseClass() {
System.out.println("Parent Before Class method");
}
@AfterClass
public void afterBaseClass() {
System.out.println("Parent After Class method");
}
@BeforeMethod
public void beforeBaseMethod() {
System.out.println("Parent Before method");
}
@AfterMethod
public void afterBaseMethod() {
System.out.println("Parent After method");
}
}
Class Test cases:
package com.anhtester.Bai10_Annotations;
import com.anhtester.common.BaseTest;
import org.testng.annotations.*;
public class DemoAnnotation extends BaseTest {
@BeforeSuite
public void beforeSuite() {
System.out.println("Before Suite");
}
@AfterSuite
public void afterSuite() {
System.out.println("After Suite");
}
@BeforeTest
public void beforeTest() {
System.out.println("Before Test");
}
@AfterTest
public void afterTest() {
System.out.println("After Test");
}
@BeforeClass
public void beforeClass() {
System.out.println("Before Class");
}
@AfterClass
public void afterClass() {
System.out.println("After Class");
}
@BeforeGroups(groups = {"testOne"})
public void beforeGroupOne() {
System.out.println("Before Group testOne 1");
}
@AfterGroups(groups = {"testOne"})
public void afterGroupOne() {
System.out.println("After Group testOne 1");
}
@BeforeGroups(groups = {"testTwo"})
public void beforeGroupTwo() {
System.out.println("Before Group testTwo 2");
}
@AfterGroups(groups = {"testTwo"})
public void afterGroupTwo() {
System.out.println("After Group testTwo 2");
}
@BeforeMethod
public void beforeMethod() {
System.out.println("Before Method");
}
@AfterMethod
public void afterMethod() {
System.out.println("After Method");
}
@Test(groups = {"testOne"}, priority = 1, description = "Đây là test case thứ 1")
public void testOneMethod() {
System.out.println("Test method 1");
}
@Test(groups = {"testTwo"}, priority = 2)
public void testTwoMethod() {
System.out.println("Test method 2");
}
}
Và file testng.xml như lúc nảy đã chạy:
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite" verbose="1">
<test name="First Test">
<classes>
<class name="com.anhtester.Bai10_Annotations.DemoAnnotation"></class>
</classes>
</test>
</suite>
Đây là kết quả:
Thứ tự chạy khi có kế thừa (extends) sẽ là:
- Khi bắt đầu: Parent Before > Child Before
- Khi kết thúc: Child After > Parent After
✅ Annotation @Test
Đây là annotation đánh dấu Method hoặc Class trong TestNG. Nếu nó được đánh dấu cho Class thì tất cả các Method mà public thì sẽ được run, các Method không phải public sẽ không được run.
Ví dụ:
✅ Các Attribute của Annotation @Test
- alwaysRun: có giá trị mặc định là false, nó sẽ bị ignore nếu nó không có dependency method (phụ thuộc) . Nếu đặt là true thì Method sẽ được run kể cả khi các dependency method fail.
VD: @Test(alwaysRun=true) - enabled: giá trị mặc định là true. Dùng để đánh dấu method run hoặc không run. Nếu false, method đó sẽ được bỏ qua, không run. Nếu true, method đó sẽ được run.
VD: @Test(enabled=true) - description: dùng để thêm thông tin cho test. Attribute này giúp chúng ta thêm mô tả cho các test case khi mà method Name không thể diễn tả được hết.
VD: @Test(description="Check permission of Admin role") - timeOut: xác định thời gian tối đa mà test có thể run, nếu thời gian run lớn hơn thời gian đã định sẵn thì kết quả test là fail. Đơn vị là mili giây.
VD: @Test(timeOut=1000) - dataProvider: điền data vào cho test method, phục vụ cho data-driven testing (sẽ viết ở bài khác)
- dataProviderClass: điền tên class mà TestNG sẽ tìm kiếm data-provider method được nhắc đến ở attribute dataProvider. Mặc định thì nó sẽ tìm ở chính class đó hoặc class base.
- dependsOnGroups: điền list các group mà test phụ thuộc.
- dependsOnMethods: điền list các method mà test phụ thuộc. (sẽ viết ở bài khác)
Lưu ý:
- Trong 1 @Test có thể áp dụng nhiều annotation cùng với nhau.
@Test(enabled=true, description="Anh Tester Automation Testing")
public void TC_03_Multi_Attribute() {
System.out.println("Anh Tester");
}
✅ Độ ưu tiên để chạy Test trong TestNG
package com.anhtester.annotations;
import org.testng.annotations.Test;
public class Demo_Priority {
@Test(priority = 2)
public void test_method_1() {
System.out.println("Run test method 1");
}
@Test(priority = 1) //độ ưu tiên đầu tiên -> chạy test_method_2() đầu tiên
public void test_method_2() {
System.out.println("Run test method 2");
}
@Test(priority = 3)
public void test_method_3() {
System.out.println("Run test method 3");
}
}
Đoạn mã set độ ưu tiên sẽ được đặt trong annotation @Test
, với cú pháp @Test(priority={expected_order})
(expected_order : 0 .... N , số càng nhỏ thì độ ưu tiên càng lớn).
Trong ví dụ trên thì trình tự thực hiện sẽ là:
- Run test method 2
- Run test method 1
- Run test method 3
