Singleton Design Pattern là một cấu trúc code nhằm hạn chế việc khởi tạo đối tượng của một class vô tội vạ. Điều này vô cùng quan trọng trong việc define một đối tượng để control toàn bộ hệ thống. Trong automation test ta có apply nó vào việc khởi tạo đối tượng WebDriver. Trong bài viết ngày hôm nay ta sẽ cùng nhau làm rõ Singleton Pattern.
Singleton là gì
Singleton là một thể hiện (instance) duy nhất được khởi tạo và các class khác có thể gọi đến nó ( mọi lúc mọi nơi )
Đặc điểm của Singleton
- Đảm bảo chỉ có 1 thể hiện (instance) của lớp (class).
- Giúp quản lý việc truy cập tốt hơn vì chỉ có 1 thể hiện (instance) duy nhất.
- Quản lý được số lượng thể hiện (instance) của một lớp (class) trong một giới hạn chỉ định.
Các nguyên tắc cơ bản để implement Singleton pattern
- Dữ liệu instance (private và static) là đối tượng duy nhất của lớp Singleton.
- Private hoặc protected constructor nhằm hạn chế người dùng tạo instance trực tiếp từ lớp (class) bên ngoài.
- Có một method public static để return instance đã được khởi tạo ở trên.
Ok dựa trên các nguyên tắc đó ta sẽ tạo một class Singleton để quản lí WebDriver
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public class WebDriverSingleton { private static WebDriver driver; private WebDriverSingleton() { } public static WebDriver getDriver() { if (driver == null ) { System.setProperty( "webdriver.chrome.driver" , "path_to_driver" ); driver = new ChromeDriver(); } return driver; } public static void closeDriver() { if (driver != null ) { driver.quit(); driver = null ; } } } |
Class BaseTest phụ trách cho việc khởi tạo và dọn dẹp instance
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import org.junit.After; import org.junit.Before; import org.openqa.selenium.WebDriver; public class BaseTest { protected WebDriver driver; @Before public void setUp() { driver = WebDriverSingleton.getDriver(); driver.manage().window().maximize(); } @After public void tearDown() { WebDriverSingleton.closeDriver(); } } |
Class test login
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | import org.junit.Test; import org.openqa.selenium.By; public class LoginTest extends BaseTest { @Test public void testValidLogin() { driver.findElement(By.id( "username" )).sendKeys( "testuser" ); driver.findElement(By.id( "password" )).sendKeys( "password" ); driver.findElement(By.id( "loginButton" )).click(); // Xác minh nếu đăng nhập thành công (VD: tìm element chỉ có khi đã login) boolean isLoggedIn = driver.findElements(By.id( "welcomeMessage" )).size() > 0 ; assertTrue( "Login was unsuccessful" , isLoggedIn); } @Test public void testInvalidLogin() { driver.findElement(By.id( "username" )).sendKeys( "invaliduser" ); driver.findElement(By.id( "password" )).sendKeys( "wrongpassword" ); driver.findElement(By.id( "loginButton" )).click(); // Xác minh nếu hiển thị thông báo lỗi boolean isErrorDisplayed = driver.findElements(By.id( "errorMessage" )).size() > 0 ; assertTrue( "Error message was not displayed" , isErrorDisplayed); } } |
Class test search
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | import org.junit.Test; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; public class SearchTest extends BaseTest { @Test public void testValidSearch() { WebElement searchBox = driver.findElement(By.id( "searchBox" )); searchBox.sendKeys( "Selenium" ); searchBox.submit(); // Kiểm tra nếu kết quả tìm kiếm có hiển thị boolean isResultDisplayed = driver.findElements(By.className( "searchResult" )).size() > 0 ; assertTrue( "Search results were not displayed" , isResultDisplayed); } @Test public void testEmptySearch() { WebElement searchBox = driver.findElement(By.id( "searchBox" )); searchBox.clear(); searchBox.submit(); // Kiểm tra nếu hiển thị thông báo không có kết quả boolean isNoResultDisplayed = driver.findElements(By.id( "noResultMessage" )).size() > 0 ; assertTrue( "No results message was not displayed" , isNoResultDisplayed); } } |
BaseTest
chứa các phương thức setUp()
và tearDown()
để chuẩn bị môi trường test và đóng WebDriver sau mỗi test case.Các lớp test (LoginTest
, SearchTest
) đều kế thừa từ BaseTest
và sử dụng chung một instance WebDriver từ WebDriverSingleton
.Điều này đảm bảo chỉ có một instance của WebDriver được tạo trong toàn bộ suite test, tối ưu hiệu suất và tránh các vấn đề do khởi tạo nhiều instance.
Kết luận
Công bằng mà nói mình không hiểu quá sâu về Singleton này ( thực tế khi code auto mình cũng không apply technique này), có rất nhiều cách để triển khai design pattern này cách mình trình bày ở trên khá đơn giản và dễ hiểu, nếu các bạn muốn tìm hiểu sâu hơn về design pattern này chắc vẫn cần thầy giáo Google chỉ dạy thêm hihi