前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java Selenium 自动化测试实践探索

Java Selenium 自动化测试实践探索

原创
作者头像
花花Binki
发布2024-10-26 23:55:22
1221
发布2024-10-26 23:55:22
举报
文章被收录于专栏:岚的工作随笔
封面
封面

前言

之前我们提到了 TDD 这一软件工程的技巧,其中很重要的一点就是自动化测试。在 Java 语言中,如果是对部分代码进行测试,通常会选择使用 Junit 。但毕竟是单元测试,对于结合了前后端的具体功能还是有限。通常这一部分会交给测试人员。那么有没有一款自动操作网页的测试工具呢?今天的主角就是其中之一。

简介

W3C,这个制定标准化Web的组织,给浏览器制定了很多标准。其中就有一个 WebDriver 。这是一种原生的方式浏览网页,同时开放了很多交互API。通过这些API可以自动操作网页,Selenium就是一个集大成者。

Selenium 执行原理
Selenium 执行原理

基础准备

初始化

Java 中所有的对象都可以 new 出来,Selenium也不例外,但这里不叫Selenium,而是需要使用具体的 WebDriver。

WebDriver 是接口

下面就选用 Windows 都有的 Edge 浏览器对应的 EdgeDriver。并初始化连接到selenium官方提供的测试网站。

代码语言:java
复制
    EdgeDriver driver = new EdgeDriver();
    // 打开示例网站
    driver.get("https://www.selenium.dev/selenium/web/web-form.html");

其中的 EdgeDriver 还可以使用一些参数启动,比如 EdgeOptions 。

代码语言:java
复制
    EdgeOptions edgeOptions = new EdgeOptions();
    // 设置HeadLess模式
    edgeOptions.addArguments("--headless");

页面基础

以下是一些常用的方法,写测试或调试时可能会用上。

  • title

字面意思,就是当前页面的Title。

代码语言:java
复制
// Web form
driver.getTitle();
  • windowHandle

窗口句柄,当要进行多个窗口来回切换的时候,需要用此来进行切换。返回值是字符串。

代码语言:java
复制
// B52E41648853DEA0F17A9519FBAD43DA
String aHandle = driver.getWindowHandle()
...
// 切换到aHandle
driver.switchTo().window(aHandle);
  • PageSource

返回当前页面的源码,不会再获取js,css等。

⚠️如果有iframe嵌入其中,是不显示内部代码的。需要切换到frame中。

  • Navigation 方法

包含一系列的原生导航。back 后退,forward 前进,to 跳转,refresh 刷新。

driver.navigate().back();

案例演示

下面以官方提供的Demo为例:

官方示例
官方示例

input text 的操作

官方示例中,input的代码如下

代码语言:html
复制
<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等基础定位要素。

代码语言:java
复制
		driver.findElement(By.id("my-text-id"));
		driver.findElement(By.name("my-text"));
		driver.findElement(By.xpath("//input[@myprop='myvalue']"));

xpath

前面两个从语意就很方便理解,这里就第三个展开说明:

从简介中我们得知,Selenium 并不是内置浏览器交给开发者操控,而是使用 REST API 通信给驱动,发送的是 JSON ,返回的是 HTML。

如果有前端基础,用过Jquery 等 JavaScript 库,会见过类似的用法:

代码语言:javascript
复制
$('input[myprop="myvalue"]')

这种语法称之为 Xpath (XML Path Language)XML 路径语言。

// 是相对路径,是使用 xpath 的常用手段,如果想用绝对路径,可以使用/ 开头,但需要更全的路径:

/html/.../label/input0

交互

通过元素定位后,他的返回值为org.openqa.selenium.WebElement。

自带一些基础交互方法。

代码语言:java
复制
// 点击 并不是所有都可点击
void click();
// 提交
void submit();
// 模拟按键,请查看org.openqa.selenium.Keys
void sendKeys(CharSequence... keysToSend);
// 清空输入内容
void clear();
...

工具类

selenium 很强大,但并不是很方便用,所以需要进行简易封装。

代码语言:java
复制
/**
 * 向指定的网页元素输入文本。
 * 
 *  @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

找不到元素的原因很多

  • xpath的拼写有误
  • 当前WindowHandle不在对应画面
  • 元素在frame中,需要driver.switchTo().frame("Frame 名")

StaleElementReferenceException

这种情况比较难发生。说明定位元素时他存在,但由于某些处理,比如画面刷新,点击时不存在了。

加大容错

高加载速度的页面中,这些元素基本不会有什么问题。但自动化操作在多变的网页操作中,如果不加以针对,经常会出现各种各样的 Bug。

高加载速度:网速快,页面逻辑简单。

等待页面

有时,需要等待页面加载完成,才会有对应元素。Selenium 对此并没有直接的方法,不过可以采用 JavaScript 的方式:

代码语言:java
复制
/**
 * 等待页面加载完成的方法。
 * @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);
}

等待元素

即使页面加载完毕,元素也有可能未出现,需要再根据自定义条件:

代码语言:java
复制
// 可见作为条件
ExpectedConditions.visibilityOfElementLocated(by);
// 不可见作为条件
ExpectedConditions.invisibilityOfElementLocated(by);

可见与不可见的条件包含两种情况,一个是元素的 display 为 none ,一个是页面不包含该元素。

窗口等待

使用driver.getWindowHandles()可以取得当前所有窗口的Handle组成的Set<String>。前端使用window.open()等打开的窗口,第一时间 Selenium 无法取得,条件表达式也没有直接有效的方法。这时可以手动模拟,等待新增窗口。

代码语言:java
复制
/**
 * 切换到新窗口的方法。
 *
 * @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 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 简介
  • 基础准备
    • 初始化
      • 页面基础
      • 案例演示
        • input text 的操作
          • xpath
          • 交互
          • 工具类
        • 加大容错
          • 等待页面
          • 等待元素
          • 窗口等待
      • 最后
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档