之前我们提到了 TDD 这一软件工程的技巧,其中很重要的一点就是自动化测试。在 Java 语言中,如果是对部分代码进行测试,通常会选择使用 Junit 。但毕竟是单元测试,对于结合了前后端的具体功能还是有限。通常这一部分会交给测试人员。那么有没有一款自动操作网页的测试工具呢?今天的主角就是其中之一。
W3C,这个制定标准化Web的组织,给浏览器制定了很多标准。其中就有一个 WebDriver 。这是一种原生的方式浏览网页,同时开放了很多交互API。通过这些API可以自动操作网页,Selenium就是一个集大成者。
Java 中所有的对象都可以 new 出来,Selenium也不例外,但这里不叫Selenium,而是需要使用具体的 WebDriver。
WebDriver 是接口
下面就选用 Windows 都有的 Edge 浏览器对应的 EdgeDriver。并初始化连接到selenium官方提供的测试网站。
EdgeDriver driver = new EdgeDriver();
// 打开示例网站
driver.get("https://www.selenium.dev/selenium/web/web-form.html");
其中的 EdgeDriver 还可以使用一些参数启动,比如 EdgeOptions 。
EdgeOptions edgeOptions = new EdgeOptions();
// 设置HeadLess模式
edgeOptions.addArguments("--headless");
以下是一些常用的方法,写测试或调试时可能会用上。
字面意思,就是当前页面的Title。
// Web form
driver.getTitle();
窗口句柄,当要进行多个窗口来回切换的时候,需要用此来进行切换。返回值是字符串。
// B52E41648853DEA0F17A9519FBAD43DA
String aHandle = driver.getWindowHandle()
...
// 切换到aHandle
driver.switchTo().window(aHandle);
返回当前页面的源码,不会再获取js,css等。
⚠️如果有iframe嵌入其中,是不显示内部代码的。需要切换到frame中。
包含一系列的原生导航。back 后退,forward 前进,to 跳转,refresh 刷新。
driver.navigate().back();
下面以官方提供的Demo为例:
官方示例中,input的代码如下
<label class="form-label w-100">Text input
<input type="text" class="form-control" name="my-text" id="my-text-id" myprop="myvalue">
</label>
以上给出的要素很全,可以根据name、id、自定义属性myprop等基础定位要素。
driver.findElement(By.id("my-text-id"));
driver.findElement(By.name("my-text"));
driver.findElement(By.xpath("//input[@myprop='myvalue']"));
前面两个从语意就很方便理解,这里就第三个展开说明:
从简介中我们得知,Selenium 并不是内置浏览器交给开发者操控,而是使用 REST API 通信给驱动,发送的是 JSON ,返回的是 HTML。
如果有前端基础,用过Jquery 等 JavaScript 库,会见过类似的用法:
$('input[myprop="myvalue"]')
这种语法称之为 Xpath (XML Path Language)XML 路径语言。
//
是相对路径,是使用 xpath 的常用手段,如果想用绝对路径,可以使用/
开头,但需要更全的路径:
/html/.../label/input0
通过元素定位后,他的返回值为org.openqa.selenium.WebElement。
自带一些基础交互方法。
// 点击 并不是所有都可点击
void click();
// 提交
void submit();
// 模拟按键,请查看org.openqa.selenium.Keys
void sendKeys(CharSequence... keysToSend);
// 清空输入内容
void clear();
...
selenium 很强大,但并不是很方便用,所以需要进行简易封装。
/**
* 向指定的网页元素输入文本。
*
* @param driver WebDriver实例,用于与浏览器交互
* @param by 定位器,用于定位网页元素
* @param text 需要输入的文本内容
*/
public static void inputText(WebDriver driver, By by, String text) {
try {
WebElement element = driver.findElement(by);
// 清除元素中的现有文本
element.clear();
// 输入新文本
element.sendKeys(text);
} catch (NoSuchElementException e) {
System.out.println("找不到元素: " + by);
} catch (StaleElementReferenceException e) {
System.out.println("元素已过时: " + by);
}
}
如果直接敲入10 - 14 行,IDE 不会直接提示需要 catch。这样设计的原因是想直接暴漏出Exception,防止后续步骤出现预想之外的错误。以上是展示可能出现的问题。
NoSuchElementException
找不到元素的原因很多
StaleElementReferenceException
这种情况比较难发生。说明定位元素时他存在,但由于某些处理,比如画面刷新,点击时不存在了。
高加载速度的页面中,这些元素基本不会有什么问题。但自动化操作在多变的网页操作中,如果不加以针对,经常会出现各种各样的 Bug。
高加载速度:网速快,页面逻辑简单。
有时,需要等待页面加载完成,才会有对应元素。Selenium 对此并没有直接的方法,不过可以采用 JavaScript 的方式:
/**
* 等待页面加载完成的方法。
* @param driver WebDriver实例。
* @param timeout 等待的最大时间(秒)。
*/
public void waitForPageLoad(WebDriver driver, int timeout) {
// 自定条件
ExpectedCondition<Boolean> pageLoadCondition = new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
}
};
// 等待
WebDriverWait wait = new WebDriverWait(driver, timeout);
wait.until(pageLoadCondition);
}
即使页面加载完毕,元素也有可能未出现,需要再根据自定义条件:
// 可见作为条件
ExpectedConditions.visibilityOfElementLocated(by);
// 不可见作为条件
ExpectedConditions.invisibilityOfElementLocated(by);
可见与不可见的条件包含两种情况,一个是元素的 display 为 none ,一个是页面不包含该元素。
使用driver.getWindowHandles()
可以取得当前所有窗口的Handle组成的Set<String>
。前端使用window.open()
等打开的窗口,第一时间 Selenium 无法取得,条件表达式也没有直接有效的方法。这时可以手动模拟,等待新增窗口。
/**
* 切换到新窗口的方法。
*
* @param driver WebDriver实例。
* @param beforeHandles 切换窗口前的窗口句柄集合。
*/
public static void switchToNewWindow(WebDriver driver, Set<String> beforeHandles) {
int i = 0;
while (i < 30) {
Set<String> windowHandles = driver.getWindowHandles();
if (windowHandles.size() > beforeHandles.size()) {
break;
}
sleep(1000);
i++;
}
Set<String> windowHandles = driver.getWindowHandles();
// 差分两个Set,得到新窗口的句柄
windowHandles.removeAll(beforeHandles);
driver.switchTo().window(windowHandles.iterator().next());
}
还有一些建议:
①代码操作大多时候是确认的结果,除了 AI 和 Selenium。
②假如,你在内网操作,公司墙了很多网站,请提前下载好浏览器对应版本的驱动。
C:\Users\{用户}\.cache\selenium\msedgedriver\win64\{浏览器版本}
msedgedriver.exe
③在本地多次调试时,记得清理后台多余的msedgedriver.exe
,意外的代码终止并不会让驱动停止,过多次的启动会占用闲置端口和内存。
④注意开发自动化测试的周期。Selenium 版本,driver 版本和浏览器版本不对应,代码都有可能操作出现意外。
⑤多留log,必要时可以截图。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。