Selenium
Selenium是一個用於Web應用程式自動化測試的開源工具套件。它主要用於以下目的:
- 瀏覽器自動化:Selenium能夠模擬真實使用者在不同瀏覽器(如Chrome、Firefox、IE/Edge等)中的互動行為,透過程式設計方式控制瀏覽器執行一系列操作,例如點選按鈕、填寫表單、導航頁面等。
- 相容性測試:透過編寫指令碼在多種瀏覽器和作業系統環境下執行測試,確保Web應用在不同組合下都能正確工作。
- 功能測試:建立迴歸測試用例來驗證軟體功能是否按預期工作,以及使用者需求是否得到滿足。
- 端到端測試:進行從使用者介面到後端服務的整體流程測試,檢查系統元件間的整合效果。
- 支援多種語言:Selenium WebDriver API 可以使用Java、Python、C#、Ruby等多種程式語言實現測試指令碼。
- 與DevTools整合:在較新的Selenium版本中,提供了對Chromium內嵌的Chrome DevTools的支援,允許開發者執行更深層次的瀏覽器操作和除錯任務。
總的來說,Selenium幫助開發團隊提高Web應用的質量保障效率,透過自動化測試減少手動測試的重複性和複雜性,並有助於持續整合和持續部署(CI/CD)流程的實施。
下載Selenium
Selenium的下載通常分為兩個步驟:首先,你需要下載並安裝適用於你開發環境的Selenium WebDriver庫(針對不同程式語言有不同的庫);其次,根據你的測試需求下載對應瀏覽器的驅動程式。
以下是一些常見程式語言中Selenium WebDriver庫的下載和安裝方式:
Python:
使用pip工具進行安裝:
pip install selenium
Java:
在Maven專案中新增如下依賴到pom.xml檔案:
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>最新版本號</version>
</dependency>
或在Gradle專案中新增:
implementation 'org.seleniumhq.selenium:selenium-java:最新版本號'
如果不使用構建工具,可以直接從Maven倉庫下載selenium-java.jar包。
C# :
對於.NET環境,可以透過NuGet包管理器在Visual Studio中安裝Selenium.WebDriver NuGet包。
下載瀏覽器驅動
安裝完WebDriver庫後,接下來需要下載瀏覽器驅動,例如:
- ChromeDriver:從ChromeDriver官網(https://sites.google.com/a/chromium.org/chromedriver/downloads)下載與你的Chrome瀏覽器版本相匹配的驅動。
- GeckoDriver(Firefox):訪問GeckoDriver GitHub釋出頁面(https://github.com/mozilla/geckodriver/releases)下載適合你Firefox版本的驅動。
- EdgeDriver 或 IEDriverServer:分別在Microsoft WebDriver下載頁面和Selenium官方IEdriver下載頁獲取相應驅動。
將下載的瀏覽器驅動放在系統的PATH路徑下,或者在程式碼中明確指定驅動路徑,即可配合WebDriver開始編寫自動化測試指令碼了。
獲取最新版本的chrome和chromeDriver https://sites.google.com/a/chromium.org/chromedriver/downloads
Java程式碼
yml配置檔案
system:
#驅動資訊
driver:
mode: 1 # 驅動模式(0:本地 1:遠端)
headless: 0 #是否顯示瀏覽器(0:顯示 1:不顯示)
name: webdriver.chrome.driver
path: D:\drivers\chromedriver-win64\chromedriver.exe
# 遠端driver驅動地址
remoteUrl: http://127.0.0.1:9515
systemUrl: http://目標伺服器地址
工具類:包含開啟、關閉、重新整理瀏覽器功能
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.net.ConnectException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@Slf4j
@Component
public class WebDriverUtils {
@Autowired
private Environment env;
/**
* 是否顯示瀏覽器(0:否 1:是)
*/
private static String headless;
/**
* 驅動遠端地址
*/
private static String driverRemoteUrl;
private static String systemUrl;
@PostConstruct
public void init() {
headless = env.getProperty("system.driver.headless");
driverRemoteUrl = env.getProperty("system.driver.remoteUrl");
systemUrl = env.getProperty("system.driver.systemUrl");
}
/**
* 等待時間
*/
public final static int timeSeconds = 10;
private static String getRemoteUrl(String driverRemoteUrl) {
String remoteUrl = null;
if (StringUtils.isNotBlank(driverRemoteUrl)) {
if (driverRemoteUrl.contains(",")) {
String[] split = driverRemoteUrl.split(",");
remoteUrl = split[(new Random()).nextInt(split.length)];
} else {
remoteUrl = driverRemoteUrl;
}
}
return remoteUrl;
}
/**
* 獲取驅動
*
* @return
* @throws ConnectException
*/
public static WebDriver getDriver() {
log.info("進入啟動瀏覽器");
ChromeOptions chromeOptions = new ChromeOptions();
// 設定瀏覽器是否可見
if ("1".equals(headless)) {
chromeOptions.addArguments("--headless");
chromeOptions.addArguments("--disable-gpu");
// headless模式下必須設定這兩個引數,否則會報連線超時
chromeOptions.addArguments("--proxy-server='direct://'");
chromeOptions.addArguments("--proxy-bypass-list=*");
} else {
chromeOptions.addArguments("--no-sandbox");
}
WebDriver driver = null;
log.info(String.format("driverRemoteUrl:%s", driverRemoteUrl));
DesiredCapabilities dc = DesiredCapabilities.chrome();
dc.setCapability(ChromeOptions.CAPABILITY, chromeOptions);
try {
driver = new RemoteWebDriver(new URL(getRemoteUrl(driverRemoteUrl)), dc);
} catch (Exception e) {
e.printStackTrace();
throw new ApplicationException(-1, "RemoteWebDriver連線遠端驅動失敗");
}
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(timeSeconds, TimeUnit.SECONDS);
driver.manage().timeouts().pageLoadTimeout(timeSeconds, TimeUnit.SECONDS);
driver.manage().timeouts().setScriptTimeout(timeSeconds, TimeUnit.SECONDS);
return driver;
}
/**
* 關閉瀏覽器驅動
*
* @param driver
*/
public static void quitBrowser(WebDriver driver) {
try {
if (driver != null) {
driver.close();
driver.quit();
log.info("瀏覽器關閉成功");
}
} catch (Exception e) {
log.error("瀏覽器關閉異常 - {}", e.getMessage());
throw new ApplicationException(-1, e.toString());
}
}
public static synchronized boolean openBrowser(WebDriver driver) {
log.info("即將開啟瀏覽器");
try {
driver.get(systemUrl);
return true;
} catch (Exception e) {
log.error("開啟瀏覽器異常,{}",e);
return false;
}
}
/**
* 重新整理瀏覽器
* @param driver
* @return
*/
public static synchronized void refreshBrowser(WebDriver driver) {
driver.navigate().refresh();
}
private static boolean alertExists(float timeout, WebDriver driver) {
long start = System.currentTimeMillis();
while ((System.currentTimeMillis() - start) < timeout * 1000) {
try {
driver.switchTo().alert();
return true;
} catch (Exception e) {
}
}
return false;
}
/**
* 關閉登入訊息提醒彈窗
*
* @param timeout
* @param driver
*/
private static void closePrompt(float timeout, WebDriver driver) {
long start = System.currentTimeMillis();
while ((System.currentTimeMillis() - start) < timeout * 1000) {
try {
close_ymPrompt(driver);
} catch (Exception e) {
log.error("無法找到登陸訊息提醒彈窗");
} finally {
sleep("500");
}
}
}
public static void close_ymPrompt(WebDriver driver) {
WebElement closePromptEle = driver.findElement(By.className("ymPrompt_close"));
closePromptEle.click();
}
/**
* 點選彈窗
*
* @param driver
*/
private static void clickConfirmEle(WebDriver driver) {
try {
long start = System.currentTimeMillis();
// 點選確定
while (System.currentTimeMillis() - start < 2 * 1000) {
WebElement saveconfirm = driver.findElement(By.id("ymPrompt_btn_0"));
saveconfirm.click();
sleep("500");
}
} catch (Exception e) {
log.debug("沒有確定彈窗");
}
}
/**
* 獲取屬性值
*
* @param eleName
* @param attributeName
* @return
*/
public static String getAttributeByEle(WebElement webElement, String eleName, String attributeName) {
WebElement webEle = webElement.findElement(By.name(eleName));
return webEle.getAttribute(attributeName);
}
/**
* 休眠
*
* @param millis
*/
public static void sleep(String millis) {
try {
long waittingTime1 = Long.parseLong(millis);
Thread.sleep(waittingTime1);
} catch (Exception e) {
e.printStackTrace();
}
}
public static String findWindow(WebDriver driver, String title) {// 找到屬於該標題的視窗控制代碼
Boolean find = false;
String findhandle = null;
long start = System.currentTimeMillis();
while (!find && (System.currentTimeMillis() - start) < 10 * 1000) {
Set<String> handles = driver.getWindowHandles();
for (String handle : handles) {
if (driver.switchTo().window(handle).getTitle().equals(title)) {
findhandle = handle;
find = true;
break;
}
}
}
return findhandle;
}
private static List<WebElement> findWebElements(WebDriverWait wait, String ele) {
try{
return wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.name(ele)));
}catch (Exception e){
log.error("未查詢到元素");
}
return null;
}
/**
*
* @return 當前開啟視窗的最後一個控制代碼
*/
public static String getLastHandle(WebDriver driver) {
Set<String> Allhandles = driver.getWindowHandles();//獲取當前開啟視窗的所有控制代碼
List<String> lst = new ArrayList<String>(Allhandles);
return lst.get(lst.size()-1);
}
}
模擬使用者瀏覽器操作
我把這段程式碼也放到工具類裡了
/**
* 模擬登入某個系統
* @param driver
* @param wait
* @param username
* @param password
* @return
*/
public static synchronized boolean loginSystem(WebDriver driver, WebDriverWait wait, String username,
String password) {
log.info("即將登入,頁面地址 - [{}]", systemUrl);
try {
log.info("即將登入,登入資訊 - [賬號: {}]", username);
sleep("1000");
WebElement usernameElement = driver.findElement(By.id("name"));
// 輸入使用者名稱
usernameElement.sendKeys(username);
WebElement passwordElement = driver.findElement(By.id("pwd"));
// 輸入密碼
passwordElement.sendKeys(password);
// 點選登入
log.info("點選登入");
WebElement loginElement = driver.findElement(By.id("login"));
loginElement.click();
// 等待2秒,防止目標系統反應過慢
sleep("2000");
//獲取彈框值判斷是否登入成功
Alert alert = driver.switchTo().alert();
String text = alert.getText();
alert.accept();
log.info("登入成功");
return true;
} catch (Exception e) {
log.error("登入異常,{}",e);
return false;
}
}
/**
* 模擬填充表單內容並儲存
* @param driver
* @param param
* @return
*/
public static synchronized boolean sendGzjs(WebDriver driver, MyParam param) {
try {
log.info("開始填充表單:{}", param.toString());
WebElement ndElement = driver.findElement(By.id("nd"));
// 輸入年度
ndElement.sendKeys(param.getNd());
WebElement yfElement = driver.findElement(By.id("yf"));
// 輸入月份
yfElement.sendKeys(param.getYf());
WebElement contentElement = driver.findElement(By.id("content"));
// 輸入內容
contentElement.sendKeys(param.getContent());
log.info("點選儲存");
WebElement loginElement = driver.findElement(By.id("save"));
loginElement.click();
// 等待2秒,防止目標系統反應過慢
sleep("2000");
//獲取彈框值判斷是否儲存成功
Alert alert = driver.switchTo().alert();
String text = alert.getText();
alert.accept();
if ("目標系統返回的錯誤資訊!".equals(text)) {
log.info("傳送失敗");
return false;
}
log.info("傳送成功");
return true;
} catch (Exception e) {
log.error("傳送異常,{}",e);
return false;
}
}