我们为什么需要Selenium?
回想一下,我们每次打开测试环境网页的原因是什么?是为了出单造数据、以及验证老旧的菜单及按钮,还是为了验证新菜单及按钮的场景更多?我想大多数都是为了操作已有的功能吧。就我个人而言,经常是打开系统操作固定的功能:打开浏览器->输入测试的网址->输入用户名密码->切换角色-> loop
找到对应菜单->录入类似的模板数据->点击确定 end loop;
如果是为了造数据,我们还可以通过整理sql脚本等方式,来代替繁琐的页面操作。但如果是为了回归测试呢,为了验证新代码上线后,旧的已有功能是否受到了影响呢?无论单元测试、接口测试等做的多好,但用户并操作的毕竟是页面,而不是代码,所以作为测试人员,总是需要亲自在系统操作一遍,才能放心的。
既然对已有菜单及按钮的操作,每次都如此类似,那么我们是不是可以利用一些脚本、录屏等,让计算机按既定逻辑自动去点击操作呢?事实上市面上已有挺多这类技术实现手段的,有操作windows系统、操作移动端Andorid/IOS的,还有这篇博客要介绍的,操作Web浏览器的工具 - Selenium。借助这些工具,我们可以在各个平台上,实现操作的自动化,从而释放人力。
Selenium简介
Selenium是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7,8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera,Edge等。这个工具的主要功能包括:测试与浏览器的兼容性——测试应用程序看是否能够很好得工作在不同浏览器和操作系统之上。测试系统功能——创建回归测试检验软件功能和用户需求。支持自动录制动作和自动生成.Net、Java、Perl等不同语言的测试脚本。
Selenium是一个工具包,并不是一个框架,所以它依赖其他语言去调用它,主流为使用Python或Java语言。在使用特定语言调用的同时,往往还会配合一个该语言的测试框架,如Java的TestNG框架,用于更好地管理测试数据、管理测试案例、产出测试报告、并行执行提升效率等等。
Selenium+Java+Chrome环境搭建
Selenium的jar包只有一个,非常方便,在pom文件里增加如下依赖即可:
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.0.0</version>
</dependency>
如果是非maven工程,那只能自行前往Selenium官网,下载对应jar包并导入工程。
除了Selenium的依赖包外,想要操作浏览器,还需要准备浏览器的驱动包,每个浏览器、不同版本间的包均不相同。以Chrome为例,我本地目前的浏览器版本是98.0.4758.102,则需要下载对应的驱动包,否则可能导致无法正常驱动。
Chrome驱动包下载地址:http://chromedriver.storage.googleapis.com/index.html
准备完毕后,工程结构如下:
Chrome启动的测试代码为:
public class ChromeTest {
@Test
public void testChromeStartAndVisitBaidu(){
System.setProperty("webdriver.chrome.driver", "./src/test/resources/chromedriver.exe");
//初始化一个chrome浏览器实例,实例名称叫driver
WebDriver driver = new ChromeDriver();
//最大化窗口
driver.manage().window().maximize();
//设置隐性等待时间
driver.manage().timeouts().implicitlyWait(8, TimeUnit.SECONDS);
// get()打开一个站点
driver.get("https://www.baidu.com");
//关闭并退出浏览器
driver.quit();
}
}
元素定位
个人认为,使用Selenium编写脚本过程中,最重要也是最困难的点,在于定位元素。
Selenium中常用的定位页面元素方法如下显示,并且最优先使用的定位方法显示在前面:
元素定位方式很多,特别是XPath定位方法,十分灵活,我使用经验不对,暂不做归纳分享,待后续补充。这里提供一个通过百度,找到我CSDN博客的自动化操作示例:
public class ChromeTest {
@Test
public void testChromeStartAndVisitBaidu(){
System.setProperty("webdriver.chrome.driver", "./src/test/resources/chromedriver.exe");
//初始化一个chrome浏览器实例,实例名称叫driver
WebDriver driver = new ChromeDriver();
//最大化窗口
driver.manage().window().maximize();
//设置隐性等待时间
driver.manage().timeouts().implicitlyWait(8, TimeUnit.SECONDS);
// get()打开一个站点
driver.get("https://baidu.com");
String firstHandle = driver.getWindowHandle();
driver.findElement(By.id("kw")).sendKeys("再来一块红烧肉CSDN");
driver.findElement(By.id("su")).click();
driver.findElement(By.partialLinkText("再来一块红烧肉_CSDN")).click();
Set<String> allHandles = driver.getWindowHandles();
for (String handle:allHandles) {
if(!handle.equals(firstHandle)){
driver.switchTo().window(handle);
}
}
driver.findElement(By.xpath("//a[text()='关注']")).click();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//关闭并退出浏览器
driver.quit();
}
}
POM页面对象模型
Selenium使用时,大多都是以面向过程的形式编写的代码。而一个站点包含那么多页面,而每个页面又有那么多的元素,如果全部以面向过程的形式编写,则每次都需要重新定位,代码复用率特别低。
Page Object Model(POM) 是selenium代码的一种设计思想,其核心就是将每个页面看作一个类,则页面中的元素则为类的成员变量;页面提供的功能/动作,则作为类的方法。以这样的方式建模封装,则在使用时直接调用方法,复用已有的元素定位等代码,省去不少工作量。
以一个登录页面为例子,一共三个元素,均以成员变量形式定义,登录动作则以方法形式提供。这样,调用页面的登录方法时,只需要传入用户名和密码即可,登录成功还会返回主页的对象,继续在主页对象想调用后续操作即可,以此类推。
public class LoginPage extends BasePage{
private By username = By.id("username");
private By password = By.id("password");
private By signIn = By.xpath("//input[@value='登录']");
public HomePage login(String userName,String password){
findElementAndSendKey(username,userName);
findElementAndSendKey(password,password);
findElementAndClick(signIn);
return new HomePage();
}
}