Page Factory rồi lại Factory Design Pattern nghe cứ giống giống nhau, vậy liệu chúng có giống nhau hay không ? Trong bài viết hôm nay chúng ta sẽ cùng làm rõ với nhau Factory Design Pattern là gì, dùng pattern này thì mang lại lợi ích gì nhé.
Trước hết định nghĩa, Factory Design Pattern là một cấu trúc code giúp chúng ta khởi tạo một đối tượng mà không cần khởi tạo cụ thể class đó. Trong automation test, chúng ta phải làm việc với nhất nhiều class page object ( HomePage, LoginPage…) thay vì phải khởi tạo cụ thể class đó bằng toán tử new HomePage(), new LoginPage() chúng ta sẽ gọi một FactoryClass để trả về đối tượng cụ thể cần sử dụng.
Trong automation test, Factory Design Pattern thường được dùng để quản lí khởi tạo các Page Object và WebDriver. Mình sẽ trình bày cả 2 trong bài viết này
Apply cho việc khởi tạo Page Object
Như ở bài Page Object Model mình đã trình bày, bài hôm nay mình vẫn dựa tiếp vào 2 class đã tạo ở bài đó để viết tiếp cho việc apply Factory Design Pattern. Bạn nào chưa đọc thì có thể xem ở đây nhé
https://duyphamnotes.com/testing-knowledge/page-object-model-va-page-factory-trong-automation-test/
Như bài hôm trước ta đã có 2 class Page Object như thế này
package browserStackPages;
import static org.testng.Assert.assertEquals;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class BrowserStackHomePage {
WebDriver driver;
By Header=By.xpath("//h1");
By getStarted=By.xpath("//*[@id='signupModalProductButton']");
public BrowserStackHomePage(WebDriver driver) {
this.driver=driver;
}
public void veryHeader() {
String getheadertext=driver.findElement(Header).getText();
assertEquals("App & Browser Testing Made Easy", getheadertext);
}
public void clickOnGetStarted() {
driver.findElement(getStarted).click();
}
}
package browserStackPages;
import static org.testng.Assert.assertEquals;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class BrowserStackSignUpPage {
WebDriver driver;
By Header = By.xpath("//h1[contains(text(), 'Create')]");
By userName = By.xpath("//*[@id='user_full_name']");
By businessEmail = By.xpath("//*[@id='user_email_login']");
By password = By.xpath("//*[@id='user_password']");
public BrowserStackSignUpPage(WebDriver driver) {
this.driver = driver;
}
public void veryHeader() {
String getheadertext = driver.findElement(Header).getText().trim();
assertEquals("Create a FREE Account", getheadertext);
}
public void enterFullName(String arg1) {
driver.findElement(userName).sendKeys(arg1);
}
public void enterBusinessEmail(String arg1) {
driver.findElement(businessEmail).sendKeys(arg1);
}
public void enterPasswrod(String arg1) {
driver.findElement(password).sendKeys(arg1);
}
}
Bây giờ ta sẽ tạo một class Factory để handle việc khởi tạo Object cho 2 class Page Object trên
package browserStackPages;
import org.openqa.selenium.WebDriver;
public class PageFactoryManager {
// Method để khởi tạo BrowserStackHomePage
public static BrowserStackHomePage getHomePage(WebDriver driver) {
return new BrowserStackHomePage(driver);
}
// Method để khởi tạo BrowserStackSignUpPage
public static BrowserStackSignUpPage getSignUpPage(WebDriver driver) {
return new BrowserStackSignUpPage(driver);
}
}
Trong class implement testcase bạn chỉ cần sửa như thế này nữa là xong
package browserStackSetup;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import browserStackPages.BrowserStackHomePage;
import browserStackPages.BrowserStackSignUpPage;
public class BrowserStackSetup {
String driverPath = "C:\\geckodriver.exe";
WebDriver driver;
BrowserStackHomePage objBrowserStackHomePage;
BrowserStackSignUpPage objBrowserStackSignUpPage;
@BeforeTest
public void setup() {
System.setProperty("webdriver.chrome.driver", "C:\\BrowserStack\\chromedriver.exe");
driver = new ChromeDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("https://www.browserstack.com/");
}
@Test(priority = 1)
public void navigate_to_homepage_click_on_getstarted() {
objBrowserStackHomePage = PageFactoryManager.getHomePage(driver);
objBrowserStackHomePage.veryHeader();
objBrowserStackHomePage.clickOnGetStarted();
}
@Test(priority = 2)
public void enter_userDetails() {
objBrowserStackSignUpPage = PageFactoryManager.getSignUpPage(driver);
objBrowserStackSignUpPage.veryHeader();
objBrowserStackSignUpPage.enterFullName("TestUser");
objBrowserStackSignUpPage.enterBusinessEmail("TestUser@gmail.com");
objBrowserStackSignUpPage.enterPasswrod("TestUserPassword");
}
@AfterTest
public void afterTest() {
driver.quit();
}
}
Yes vậy là ta đã apply xong PageFactoryManager vào rùi nè, bạn có thắc mắc ủa vậy có khác quái gì đâu, số lượng dòng code vẫn thế lại còn đẻ ra thêm 1 class làm gì zậy. Okie vậy ta sẽ xem lợi ích của việc apply Factory Design Pattern là gì
Lợi ích:
- Tắng tính tập trung: việc khởi tạo các đối tượng của Page Object đều tập trung hết ở class PageFactoryManager
- Tăng khả năng tái sử dụng: gọi lại dùng ở mọi nơi
- Giảm lặp code: không cần call hàm khởi tạo ở class testcase
- Duy trì khả năng maintain code: nếu phát sinh thêm một class Page Object chỉ cần thêm một hàm khởi tạo trong PageFactoryManager
Okie vậy xong ví dụ đầu, như đầu bài mình đã nói, pattern này còn áp dụng cho việc quản lí WebDriver nữa, lets go nào
Apply cho việc handle WebDriver
Đại loại mình sẽ xây dựng một class DriverManagerFactory cho việc quản lí WebDriver. Các class testcase chỉ việc gọi hàm getBrowser() để gọi driver cần dùng.
Một enum để chứa các Browser name hay dùng ( class Enum là gì nào rảnh viết chi tiết nhá )
package core;
public enum BrowserList {
CHROME, FIREFOX, EDGE, SAFARI, OPERA, HEAD_CHROME, HEAD_FIREFOX ;
}
class DriverManagerFactory để chứa việc khởi tạo driver nào
package core;
import io.github.bonigarcia.wdm.WebDriverManager;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.Point;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.edge.EdgeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
public class DriverFactoryManager {
WebDriver driver;
public static WebDriver getBrowserDrive(String browserName){
BrowserList browser = BrowserList.valueOf(browserName.toUpperCase());
switch (browser){
case CHROME :
driver = new ChromeDriver();
break;
case EDGE :
driver = new EdgeDriver();
break;
case FIREFOX :
driver = new FirefoxDriver();
break;
case SAFARI :
driver = WebDriverManager.safaridriver().create();
break;
case OPERA :
driver = WebDriverManager.operadriver().create();
break;
default:
throw new RuntimeException("Pls enter the correct Browser name");
}
driver.manage().window().setPosition(new Point(0,0));
driver.manage().window().setSize(new Dimension(1920,1080));
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(15));
return driver;
}
}
Ok ngon rùi apply vào file testcase thôi
package browserStackSetup;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import browserStackPages.BrowserStackHomePage;
import browserStackPages.BrowserStackSignUpPage;
public class BrowserStackSetup {
WebDriver driver;
BrowserStackHomePage objBrowserStackHomePage;
BrowserStackSignUpPage objBrowserStackSignUpPage;
@BeforeTest
public void setup() {
driver = DriverFactoryManager.getBrowserDrive("FIREFOX");
driver.get("https://www.browserstack.com/");
}
@Test(priority = 1)
public void navigate_to_homepage_click_on_getstarted() {
objBrowserStackHomePage = PageFactoryManager.getHomePage(driver);
objBrowserStackHomePage.veryHeader();
objBrowserStackHomePage.clickOnGetStarted();
}
@Test(priority = 2)
public void enter_userDetails() {
objBrowserStackSignUpPage = PageFactoryManager.getSignUpPage(driver);
objBrowserStackSignUpPage.veryHeader();
objBrowserStackSignUpPage.enterFullName("TestUser");
objBrowserStackSignUpPage.enterBusinessEmail("TestUser@gmail.com");
objBrowserStackSignUpPage.enterPasswrod("TestUserPassword");
}
@AfterTest
public void afterTest() {
driver.quit();
}
}
Vậy là xong, hôm nay mình đã trình bày xong pattern thứ 2 trong chuỗi seri viết về các design pattern hay dùng trong automation test.