Trả lời: Selenium WebDriver là một công cụ automation testing mã nguồn mở, cho phép tương tác trực tiếp với trình duyệt web thông qua các API native của browser. WebDriver hỗ trợ nhiều ngôn ngữ lập trình như Java, Python, C#, Ruby và JavaScript.
Ví dụ code Java:
// Khởi tạo WebDriver
WebDriver driver = new ChromeDriver();
// Mở một trang web
driver.get("https://www.example.com");
// Đóng trình duyệt
driver.quit();Trả lời:
- driver.get(): Đợi trang load hoàn toàn trước khi thực hiện lệnh tiếp theo
- driver.navigate().to(): Không đợi trang load hoàn toàn và cho phép sử dụng các phương thức navigate khác
Ví dụ:
// Sử dụng get()
driver.get("https://google.com");
// Sử dụng navigate().to()
driver.navigate().to("https://google.com");
driver.navigate().back(); // Quay lại trang trước
driver.navigate().forward(); // Đi tới trang tiếp theo
driver.navigate().refresh(); // Refresh trangTrả lời: Selenium hỗ trợ 8 loại locator chính:
// 1. By ID
WebElement element = driver.findElement(By.id("email"));
// 2. By Name
WebElement element = driver.findElement(By.name("username"));
// 3. By ClassName
WebElement element = driver.findElement(By.className("btn-primary"));
// 4. By TagName
WebElement element = driver.findElement(By.tagName("button"));
// 5. By LinkText
WebElement element = driver.findElement(By.linkText("Click Here"));
// 6. By PartialLinkText
WebElement element = driver.findElement(By.partialLinkText("Click"));
// 7. By CSS Selector
WebElement element = driver.findElement(By.cssSelector("#email.form-control"));
// 8. By XPath
WebElement element = driver.findElement(By.xpath("//input[@id='email']"));Trả lời:
| findElement() | findElements() |
|---|---|
| Trả về một WebElement | Trả về List |
| Throw NoSuchElementException nếu không tìm thấy | Trả về empty list nếu không tìm thấy |
| Tìm element đầu tiên match | Tìm tất cả elements match |
Ví dụ:
// findElement - tìm một element
WebElement button = driver.findElement(By.className("btn"));
button.click();
// findElements - tìm nhiều elements
List<WebElement> buttons = driver.findElements(By.className("btn"));
System.out.println("Số lượng button: " + buttons.size());
for(WebElement btn : buttons) {
System.out.println(btn.getText());
}Trả lời:
Implicit Wait:
// Đặt thời gian chờ ngầm định cho toàn bộ session
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));Explicit Wait:
// Chờ cho một điều kiện cụ thể
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
WebElement element = wait.until(
ExpectedConditions.visibilityOfElementLocated(By.id("submit"))
);Fluent Wait:
// Chờ với polling interval và ignore exceptions
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(Duration.ofSeconds(30))
.pollingEvery(Duration.ofSeconds(2))
.ignoring(NoSuchElementException.class);
WebElement element = wait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return driver.findElement(By.id("dynamic-element"));
}
});Trả lời:
// Chuyển sang alert
Alert alert = driver.switchTo().alert();
// Lấy text từ alert
String alertText = alert.getText();
System.out.println("Alert message: " + alertText);
// Accept alert (click OK)
alert.accept();
// Dismiss alert (click Cancel)
alert.dismiss();
// Nhập text vào prompt alert
alert.sendKeys("Test input");
alert.accept();Trả lời:
// Lưu window handle hiện tại
String mainWindow = driver.getWindowHandle();
// Lấy tất cả window handles
Set<String> allWindows = driver.getWindowHandles();
// Switch sang window mới
for(String window : allWindows) {
if(!window.equals(mainWindow)) {
driver.switchTo().window(window);
break;
}
}
// Thực hiện action trong window mới
driver.findElement(By.id("button")).click();
// Đóng window hiện tại
driver.close();
// Switch về window chính
driver.switchTo().window(mainWindow);Trả lời:
// Tìm dropdown element
WebElement dropdownElement = driver.findElement(By.id("country"));
// Tạo Select object
Select dropdown = new Select(dropdownElement);
// Chọn theo visible text
dropdown.selectByVisibleText("Vietnam");
// Chọn theo value
dropdown.selectByValue("VN");
// Chọn theo index
dropdown.selectByIndex(2);
// Lấy option đang được chọn
WebElement selectedOption = dropdown.getFirstSelectedOption();
System.out.println("Selected: " + selectedOption.getText());
// Lấy tất cả options
List<WebElement> allOptions = dropdown.getOptions();
for(WebElement option : allOptions) {
System.out.println(option.getText());
}Trả lời: POM là design pattern tách biệt logic test và page elements, giúp code dễ maintain và reusable.
Ví dụ Page Class:
public class LoginPage {
private WebDriver driver;
// Locators
@FindBy(id = "username")
private WebElement usernameField;
@FindBy(id = "password")
private WebElement passwordField;
@FindBy(xpath = "//button[@type='submit']")
private WebElement loginButton;
// Constructor
public LoginPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
// Page Methods
public void enterUsername(String username) {
usernameField.clear();
usernameField.sendKeys(username);
}
public void enterPassword(String password) {
passwordField.clear();
passwordField.sendKeys(password);
}
public HomePage clickLogin() {
loginButton.click();
return new HomePage(driver);
}
// Business Logic Method
public HomePage login(String username, String password) {
enterUsername(username);
enterPassword(password);
return clickLogin();
}
}Test Class:
public class LoginTest {
private WebDriver driver;
private LoginPage loginPage;
@BeforeMethod
public void setup() {
driver = new ChromeDriver();
driver.get("https://example.com/login");
loginPage = new LoginPage(driver);
}
@Test
public void testValidLogin() {
HomePage homePage = loginPage.login("[email protected]", "password123");
Assert.assertTrue(homePage.isUserLoggedIn());
}
@AfterMethod
public void teardown() {
driver.quit();
}
}Trả lời:
// Cách 1: Dùng Explicit Wait với custom condition
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
// Chờ jQuery AJAX hoàn thành
wait.until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
JavascriptExecutor js = (JavascriptExecutor) driver;
return (Boolean) js.executeScript("return jQuery.active == 0");
}
});
// Cách 2: Chờ element xuất hiện sau AJAX
wait.until(ExpectedConditions.presenceOfElementLocated(
By.id("ajax-loaded-content")
));
// Cách 3: Custom wait cho Angular
public void waitForAngular() {
JavascriptExecutor js = (JavascriptExecutor) driver;
String script = "return angular.element(document).injector().get('$http').pendingRequests.length === 0";
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
wait.until(driver -> js.executeScript(script).equals(true));
}Trả lời:
// Screenshot toàn màn hình
public void takeScreenshot(String fileName) {
TakesScreenshot screenshot = (TakesScreenshot) driver;
File srcFile = screenshot.getScreenshotAs(OutputType.FILE);
try {
FileUtils.copyFile(srcFile,
new File("./screenshots/" + fileName + ".png"));
} catch (IOException e) {
e.printStackTrace();
}
}
// Screenshot một element cụ thể (Selenium 4+)
public void takeElementScreenshot(WebElement element, String fileName) {
File srcFile = element.getScreenshotAs(OutputType.FILE);
try {
FileUtils.copyFile(srcFile,
new File("./screenshots/" + fileName + ".png"));
} catch (IOException e) {
e.printStackTrace();
}
}Trả lời:
File Upload:
// Cách 1: Send keys trực tiếp
WebElement uploadElement = driver.findElement(By.id("file-upload"));
uploadElement.sendKeys("/path/to/file.pdf");
// Cách 2: Dùng Robot class cho native dialog
Robot robot = new Robot();
robot.setAutoDelay(2000);
// Copy file path to clipboard
StringSelection stringSelection = new StringSelection("/path/to/file.pdf");
Toolkit.getDefaultToolkit().getSystemClipboard()
.setContents(stringSelection, null);
// Paste và Enter
robot.keyPress(KeyEvent.VK_CONTROL);
robot.keyPress(KeyEvent.VK_V);
robot.keyRelease(KeyEvent.VK_V);
robot.keyRelease(KeyEvent.VK_CONTROL);
robot.keyPress(KeyEvent.VK_ENTER);
robot.keyRelease(KeyEvent.VK_ENTER);File Download:
// Configure Chrome để auto download
HashMap<String, Object> chromePrefs = new HashMap<>();
chromePrefs.put("download.default_directory", "/path/to/download");
chromePrefs.put("download.prompt_for_download", false);
ChromeOptions options = new ChromeOptions();
options.setExperimentalOption("prefs", chromePrefs);
WebDriver driver = new ChromeDriver(options);Trả lời:
| Feature | TestNG | JUnit |
|---|---|---|
| Annotations | @BeforeSuite, @AfterSuite, @BeforeTest, @AfterTest | Không có |
| Parallel Testing | Hỗ trợ native | Cần configuration thêm |
| Data Provider | @DataProvider | @ParameterizedTest (JUnit 5) |
| Dependency Testing | @Test(dependsOnMethods) | Không hỗ trợ |
| Grouping | @Test(groups = "smoke") | @Tag (JUnit 5) |
Ví dụ TestNG:
public class TestNGExample {
@DataProvider(name = "loginData")
public Object[][] getData() {
return new Object[][] {
{"[email protected]", "pass1"},
{"[email protected]", "pass2"}
};
}
@Test(dataProvider = "loginData", groups = "smoke")
public void testLogin(String email, String password) {
// Test logic
}
@Test(dependsOnMethods = "testLogin", groups = "regression")
public void testDashboard() {
// Test logic
}
}Trả lời:
TestNG XML Configuration:
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Parallel Test Suite" parallel="tests" thread-count="3">
<!-- Parallel by methods -->
<test name="Test1" parallel="methods" thread-count="5">
<classes>
<class name="com.test.LoginTest"/>
</classes>
</test>
<!-- Parallel by classes -->
<test name="Test2" parallel="classes" thread-count="3">
<classes>
<class name="com.test.HomeTest"/>
<class name="com.test.ProfileTest"/>
</classes>
</test>
</suite>Thread-Safe WebDriver với ThreadLocal:
public class DriverManager {
private static ThreadLocal<WebDriver> driverThread = new ThreadLocal<>();
public static void setDriver(String browserName) {
if(browserName.equals("chrome")) {
driverThread.set(new ChromeDriver());
} else if(browserName.equals("firefox")) {
driverThread.set(new FirefoxDriver());
}
}
public static WebDriver getDriver() {
return driverThread.get();
}
public static void quitDriver() {
driverThread.get().quit();
driverThread.remove();
}
}Trả lời:
- Sử dụng Page Object Model
- Implement Explicit Waits thay vì Thread.sleep()
- Tạo reusable methods
- Sử dụng Data-Driven Testing
- Implement proper logging
- Handle exceptions gracefully
- Clean up resources trong @AfterMethod
Ví dụ Best Practice Implementation:
public class BaseTest {
protected WebDriver driver;
protected Logger logger = LogManager.getLogger(this.getClass());
@BeforeMethod
@Parameters({"browser", "url"})
public void setup(String browser, String url) {
logger.info("Starting test with browser: " + browser);
driver = BrowserFactory.getDriver(browser);
driver.manage().window().maximize();
driver.get(url);
}
@AfterMethod
public void teardown(ITestResult result) {
if(result.getStatus() == ITestResult.FAILURE) {
takeScreenshot(result.getName());
logger.error("Test failed: " + result.getName());
}
driver.quit();
}
protected void takeScreenshot(String testName) {
// Screenshot logic
}
}- Thực hành code: Viết code thực tế, không chỉ học lý thuyết
- Chuẩn bị project demo: Có một project automation framework hoàn chỉnh trên GitHub
- Hiểu rõ concepts: Không chỉ nhớ syntax mà phải hiểu bản chất
- Cập nhật kiến thức: Selenium 4 có nhiều features mới như Relative Locators, Chrome DevTools Protocol
- Kể về kinh nghiệm thực tế: Chuẩn bị các tình huống đã gặp và cách giải quyết