UI自动化

本地搭建Javall商城项目

安装mysql(用户名、密码设置)——安装navicat——navicat连接mysql(localhost、用户名 密码)——navicat创建数据库导入sql——部署tomcat(项目war包放在tomcat的webapps路径内修改项目的配置文件)——启动tomcat——打开本地地址

maven环境搭建

maven安装(下载、setting文件配置maven本地仓库目录和阿里云镜像仓库)——配置环境变量(maven_home、path)——验证maven安装成功——下载常用jar包(mvn help:system)——IDEA下载maven插件——eclipse/idea新建maven项目——pom文件添加依赖jar(selenium,下载失败时找到本地maven仓库删掉文件夹重新更新maven强制下载)——IDEA中设置maven——Idea配置JDK——安装浏览器驱动(chrome禁止升级、下载chromedriver驱动、配置driver环境变量建议默认位置)——检查chromedriver是否安装成功(cmd chromedriver)

Maven项目管理

Maven是项目管理工具。主要服务于基于Java平台的项目构建,依赖管理和项目信息管理。
使用Maven的好处:只需要定义一个pom.xml, 然后把源码放到默认的目录,Maven会管理依赖和构建过程

Maven仓库

Maven 本地仓库:settings.xml中配置的本地路径,存储下载的jar包
Maven 中央仓库:settings.xml中配置的镜像仓库(eg: 阿里云…)
Maven 私服:一种特殊的远程仓库,它架设在局域网内的仓库,通常作为公司的中央仓库

在这里插入图片描述

IDEA中设置maven:File—Settings——Build—Build Tools——Maven

Idea配置JDK:File—Project Structure——Project

如果chrome浏览器安装不是默认路径(C:\Program Files (x86)
\Google\Chrome\Application)的话,需要指定chrome所在的路径:

在这里插入图片描述

下载浏览器驱动(chromedriver)地址:http://chromedriver.storage.googleapis.com/index.html
将chromedriver配置到环境变量中,cmd窗口执行chromedriver有信息则配置成功

TestNG 单元测试框架

安装testNG插件

在线安装:file——settings——plugins——搜索插件名TestNG进行安装

在这里插入图片描述

手动安装:下载插件包——plugins页面选择install plugin from disk

在这里插入图片描述

下载插件后需要添加依赖jar包:
1、通过maven的pom文件添加依赖
2、手动添加依赖包(见下图):先建文件夹libs把jar包放入该文件夹,在按下图操作

在这里插入图片描述

常用注解如下
执行顺序:BeforeSuite
BeforeTest
BeforeClass
BeforeMethod
Test

@BeforeSuite: 标示此注解的方法会在当前测试集合(suite)中的任一测试用例开始运行之前执行。
@AfterSuite: 标示此注解的方法会在当前测试集合(suite)中的所有测试程序运行结束之后执行。
@BeforeTest:标示此注解的方法会在 Test 中任一测试用例开始运行前执行。
@AfterTest:标示此注解的方法会在 Test 中所有测试用例运行结束后执行。
@BeforeGroups: 标示此注解的方法会在分组测试用例的任一测试用例开始运行前执行。
@AfterGroups: 标示此注解的方法会在分组测试用例的所有测试用例运行结束后执行。
@BeforeClass: 标示此注解的方法会在当前测试类的任一测试用例开始运行前执行。
@AfterClass: 标示此注解的方法会在当前测试类的所有测试用例运行结束后执行。
@BeforeMethod: 标示此注解的方法会在每个测试方法开始运行前执行。
@AfterMethod:: 标示此注解的方法会在每个测试方法运行结束后执行。
@Test: 标示此注解的方法会被认为是一个测试方法,即一个测试用例

常用断言
assertTrue 判断是否为 true
assertFalse 判断是否为 false
assertEquals 判断是否相等,Object 类型的对象需要实现 hashCode 及 equals 方法
assertNotEquals 判断是否不相等
assertEqualsNoOrder 判断忽略顺序是否相等
assertSame 判断引用地址是否相同
assertNotSame 判断引用地址是否不相。
assertNull 判断是否为 null
assertNotNull 判断是否不为 null

测试集合
在自动化测试的执行过程中,通常会产生批量运行多个测试用例的需求,此需求称之为运行测试集合(TestSuite)。
通过 TestNG.xml 的配置,可批量运行测试用例

依赖测试
某些复杂的测试场景需要按照某个特定顺序执行测试用例,以此保证某个测试用例被执行之后才执行其它测试用例,此测试场景运行需求称之为依赖测试。
通过依赖测试,可在不同测试方法间共享数据和程序状态。
TestNG 支持依赖测试,使用 dependsOnMethods 及 dependsOnGroups 参数来实现。

用例顺序
使用参数 Priority 可实现按照特定顺序执行测试用例,1、2、3依次执行
Priority 是全局性参数,多个类中优先级相同的话容易乱,所以建议用测试用例名称排序不加Priority

数据驱动
Testng 提供了数据驱动模式,以 DataProvider 注解完成

八大定位方式

id 对应元素的id属性 By.id(“password”)

name 对应元素的name属性 By.name(“username”)

linktext 对应a表签 By.linkText(“登录”)

pertialLinkText 对应a表签,模糊匹配a表签的文本 By.partialLinkText(“登录”)

tagname

className 对应元素的class属性 By.className(“blue_btn”) class值有空格不行,可以取部分值

css selector
css:重叠样式表
绝对路径定位:html>body>footer>div ( 表签>表签)
相对路径定位: body nav (中间空格)
class属性定位:.container (.class值)
id定位: #username (#id值)
属性定位:div[role=‘dialog’][tabindex=‘-1’] 表签[属性1=‘属性值1’][属性2=‘属性值2’]

xpath
绝对路径定位:html/body/div/nav/div/div[2]/ul[2]/li[2] 不建议使用
相对路径定位://ul[@class=“nav navbar-nav user-menu navbar-right”]/li[2]
(//button)[2] ()表示定位的所以元素强制排序
//button[2] 表示同级元素的第二个
//button[text()=‘写消息’]
//*[text()=‘发送’]
(//button)[last()]

xpath轴定位:
ancestor 选取当前节点的所有先辈 //a[@id=“unread_messages”]/ancestor::ul ul是表签
ancestor-or-self 选取当前节点的所有先辈 以及当前节点本身
parent 选取当前节点父节点 //a[@id=“unread_messages”]/parent::li li是a表签的父表签
//a[@id=“unread_messages”]/… 功能与上相同
child 选取当前节点所有子元素 不常用 因为/就可以
descendant: 选取当前节点的所有后辈 //a[@id=“unread_messages”]/descendant:😗
descendant-or-self 选取当前节点的所有后辈 以及当前节点本身

following 选取文档中当前节点之后的所有节点 //div/following:😗
following-sibling 选取当前节点之后的所有同级节点
//div[@class=“wrap”]/following-sibling::footer

//[@text=“私信消息”]/…/following-sibling::[1]/*[1]
preceding 选取文档中当前节点之前的所有节点
preceding-sibling 选取当前节点之前的所有同级节点
//div[@class=“wrap”]/preceding-sibling::div[1] []内的数字倒叙排

包含 //input[contains(@type,“check”)]

元素定位不到原因
(1)页面响应太慢元素未出现,需要加等待时间
(2)元素被遮挡,页面最大化
(3)是否有iframe、新窗口打开
(4)确认元素定位是否正确

知识点

隐式等待:

  • 1、指定时间内不断查找元素,一旦找到元素不再等待,执行下行代码
  • 2、全局性的等待,仅仅对findElement方法有效 可以多次设置
driver.manage().timeouts().implicitlyWait(10,TimeUnit.SECONDS)

有了隐式等待并不是说不需要Thread.sleep()了,因为隐式等待仅仅对findElement方法有效,很多操作类的方法例如输入后点击前需要等待或页面元素本身已经加载了只是看不到需要点击框才会有输入框还是需要Thread.sleep()
隐式等待对findElements方法不生效

显式等待:

1、显示等待是针对单一元素或一组元素进行智能等待
2、可以针对元素的操作进行显示等待
3、可以针对弹框进行显示等待
4、可以针对自定义代码进行显示等待

针对元素操作的显示等待

String username = new WebDriverWait(driver,10).until(new ExpectedCondition<String>() {

    @Override
    public String apply( WebDriver webDriver) {
        return webDriver.findElement(By.xpath("//a[@class='dropdown-toggle']/span")).getText();
    }

});

针对弹框的显示等待

Alert alert = new WebDriverWait(driver, 10).until(ExpectedConditions.alertIsPresent());//在指定超时时间内等待弹框出现

//Alert alert = driver.switchTo().alert();
String text = alert.getText();//获取弹框的文字
Assert.assertEquals(text,"消息发送成功");

自定义代码的显示等待(一闪而过的提示信息也可用显示等待)

Boolean flag = new WebDriverWait(driver,10).until(new ExpectedCondition<Boolean>() {

    @Override
    public Boolean apply(WebDriver d) {
        return d.getPageSource().contains("sinRcosT");
    }

});
//获取一闪而过的提示信息
Boolean flag = new WebDriverWait(driver,10).until(new ExpectedCondition<Boolean>() {
    @Override
    public Boolean apply(WebDriver d){
        return d.getPageSource().contains("个人资料修改成功");
    }

});

失败截图,利用io包的FileUtils

org.apache.commons.io.FileUtils
File file=((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(file, new File("images/loginerror.png"));
System.out.println("登录失败");
Assert.fail(e.getMessage());

iframe切换:

iframe相当于网页里套网页,iframe表签里又有html

在这里插入图片描述

遇到iframe里的元素,先将driver切换至iframe再定位
切换方式:
1、使用元素id;
2、使用元素name;
3、使用iframe索引即第几个iframe,使用//iframe查看;
4、使用元素对象

使用id/name:driver.switchTo().frame(“ptlogin_iframe”);
使用索引:driver.switchTo().frame(0);
使用iframe表签:WebElement iframe = driver.findElement(By.tagName(“iframe”));
driver.switchTo().frame(iframe);

返回默认: driver.switchTo().defaultContent();
返回上一级: driver.switchTo().parentFrame()
检查当前页是否有iframe://iframe

window切换:

遇到元素在新打开的窗口时,先将driver切换至window再定位
1、先获取当前的windowhandle
2、操作打开新界面后,获取所有的windowhandles
3、遍历windowhandles,判断和当前的windowhandle不一样则切换windowhandle

String windowHandle1 = driver.getWindowHandle();
driver.findElement(By.linkText("Selenium3环境搭建")).click();

Set<String> windowHandles = driver.getWindowHandles();
for(String s : windowHandles){
    if(!windowHandle1.equals(s)){
        driver.switchTo().window(s);
        break;
    }
}

多个window时可以获取每个window的title,然后遍历所有的window根据title切换window

driver.get("http://ask.testfan.cn/");
driver.manage().window().maximize();
String windowHandle1 = driver.getWindowHandle();

driver.findElement(By.linkText("Selenium3环境搭建")).click();
driver.findElement(By.linkText("如何用appium设置设备的网络状态")).click();


Set<String> windowHandles = driver.getWindowHandles();
for(String s : windowHandles){
    driver.switchTo().window(s);
    String title = driver.getTitle();
    if(title.equals("Selenium3环境搭建")){
        driver.switchTo().window(s);
        break;
    }
}

根据url切换window

for(String s:windowHandles) {
   driver.switchTo().window(s);
   String url =driver.getCurrentUrl();//获取当前界面的url
   if(url.equals("http://ask.testfan.cn/article/556")) {
      break;
   }

}

Select下拉框

下拉框进行操作时首先要定位到下拉框, 再进行操作:
• Select select=new Select(driver.findElement(By.id(“XXX”)))
选择对应的选项
• select.selectByVisibleText(String) 通过页面可见文本去选择
• select.selectByValue(String) 通过html中的value值去选择
• Select.selectByIndex(Int) 通过index来选择,从0开始

WebElement province = driver.findElement(By.id("province"));
 Select select = new Select(province);
 select.selectByVisibleText("浙江");   //通过肉眼看到的下拉选项文字选择
// select.selectByIndex(2);       //通过下拉选项索引选择
// select.selectByValue("3");    //通过下拉选项的value值选择
// select.getFirstSelectedOption().getText();  //当前选择的值

Radio Button(单选按钮)

单选按钮和多选按钮都当做普通button处理即可,找到radio button或者checkbox以
后,可以通过如下方法进行操作:
• Button.click() 点击单选或者复选框
• Button.clear() 清空选项

//修改性别,哪个没被选中选哪个
List<WebElement> genders = driver.findElements(By.name("gender"));
String sexValue = "";
for(WebElement we : genders){
    if(!we.isSelected()){
        we.click();
        sexValue=we.getAttribute("value");   //获取元素的属性  期望值
        break;
    }
}
List<WebElement> genders = driver.findElements(By.xpath("//label[@class=radio-inline]"));
for(WebElement we : genders){
    if(!we.isSelected()){
        we.click();
        break;
    }
}

Checkbox(复选框)

时间组件

借助js修改日期

//修改生日
JavascriptExecutor js = (JavascriptExecutor)driver;  //js执行器
js.executeScript("document.getElementById('birthday').value='1987-05-17'");

获取元素值的js:document.getElementById(“birthday”).value
修改元素值的js:document.getElementById(“birthday”).value=“1989-09-26”

断言:分别保存修改前和修改后的数据,然后断言 或 获取页面数据断言

单选框断言

//修改性别,哪个没被选中选哪个
List<WebElement> genders = driver.findElements(By.name("gender"));
String sexValue = "";
for(WebElement we : genders){
    if(!we.isSelected()){
        we.click();
        sexValue=we.getAttribute("value");   //获取元素的属性  期望值
        break;
    }
}
点击提交信息后
//获取性别实际值
List<WebElement> genders1 = driver.findElements(By.name("gender"));
String sexActualValue = "";
for(WebElement we : genders1){
    if(we.isSelected()){
        sexActualValue=we.getAttribute("value");   //实际值
        break;
    }
}

日期框断言

//修改生日
JavascriptExecutor js = (JavascriptExecutor)driver;
js.executeScript("document.getElementById('birthday').value='1987-05-17'");
String birthday = driver.findElement(By.id("birthday")).getAttribute("value");  
//获取生日实际值
String birthdayActual = driver.findElement(By.id("birthday")).getAttribute("value");  //实际值

下拉框断言

 //修改省份
 WebElement province = driver.findElement(By.id("province"));
 Select select = new Select(province);
 select.selectByVisibleText("浙江");   //通过肉眼看到的下拉选项文字选择
 String text = select.getFirstSelectedOption().getText();      //期望值

 // select.selectByIndex(2);       //通过下拉选项索引选择
// select.selectByValue("3");    //通过下拉选项的value值选择


//获取省份实际值
WebElement province1 = driver.findElement(By.id("province"));
Select select1 = new Select(province1);
String text1 = select1.getFirstSelectedOption().getText();      //实际值
Boolean flag = new WebDriverWait(driver,10).until(new ExpectedCondition<Boolean>() {

    @Override
    public Boolean apply(WebDriver d) {
        return d.getPageSource().contains("保存会员成功");
    }

});

用例失败保存截图

}catch (Exception | Error e){
    File file = ((TakesScreenshot)(driver)).getScreenshotAs(OutputType.FILE);
    try {
        FileUtils.copyFile(file,new File("images/loginerror.png"));
    } catch (IOException e1) {
        e1.printStackTrace();
    }

    Assert.fail(e.getMessage());
}

alert弹框断言 - js弹框(开发者工具无法定位的就是js弹框,可以用开发者工具定位的弹框是模态框)

弹框不关掉无法截图

Alert alert = driver.switchTo().alert();
String text = alert.getText();//获取弹框的文字
Assert.assertEquals(text,"消息发送成功");
//  alert.accept();      //确定弹框,弹框关闭
//  alert.dismiss();     //取消弹框,弹框关闭

//如果弹框出现的慢直接切换至弹框就会有问题,因此需要显示等待
Alert alert = new WebDriverWait(driver, 10).until(ExpectedConditions.alertIsPresent());//在指定超时时间内等待弹框出现

String text = alert.getText();//获取弹框的文字
Assert.assertEquals(text,"消息发送成功");

cookie绕过(手动登录获得cookie添加到代码中)

driver.get("http://localhost:8080/javamall/admin/backendUi!main.do");
driver.manage().window().maximize();
driver.manage().deleteAllCookies();  //删除所有的cookie
Cookie cookie = new Cookie("JSESSIONID","36C07DFAB78EAD8771A550BE2FAFF754");
driver.manage().addCookie(cookie);
driver.get("http://localhost:8080/javamall/admin/backendUi!main.do");

鼠标悬浮

WebElement memMenu = driver.findElement(By.xpath("//*[text()='会员']/../.."));
Actions actions = new Actions(driver);
actions.moveToElement(memMenu).perform();
driver.findElement(By.linkText("会员列表")).click();

拖拽

拖拽的元素不在页面出现时可先点击屏幕下方的某个元素再进行拖拽或发送TAB键滑动页面

actions.sendKeys(Keys.TAB).perform();

通过元素进行拖拽

WebElement iterm1 = driver.findElement(By.xpath("//li[text()='Item 1']"));
WebElement iterm2 = driver.findElement(By.xpath("//li[text()='Item 2']"));
Actions actions = new Actions(driver);
actions.dragAndDrop(iterm1,iterm2).perform();

X轴从左到右变大,Y轴从上到下变大

WebElement iterm1 = driver.findElement(By.xpath("//li[text()='Item 1']"));
Actions actions = new Actions(driver);
actions.dragAndDropBy(iterm1,0,50).perform();//向下拖50像素

文件上传

//将图片路径放到粘贴板
StringSelection file=new StringSelection("C:\\Users\\Public\\Pictures\\Sample Pictures\\沙漠.jpg");  //将路径转换成字符串的格式
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(file, null);

Robot robot=new Robot();
//按下ctrl+v
robot.keyPress(KeyEvent.VK_CONTROL);
robot.keyPress(KeyEvent.VK_V);
//释放ctrl+v
robot.keyRelease(KeyEvent.VK_CONTROL);
robot.keyRelease(KeyEvent.VK_V);
//按下回车并释放
robot.keyPress(KeyEvent.VK_ENTER);
robot.keyRelease(KeyEvent.VK_ENTER);
  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值