目录
selenium编写的自动化脚本是如何打开浏览器的(selenium、Driver、浏览器三者之间的关系)
前言
本篇博客我们将学习自动化测试以及如何使用工具编写自动化测试
什么是自动化测试
自动化测试指软件测试的自动化,在预设状态下运行应用程序或者系统,预设条件包括正常和异常,最后评估运行结果。将人为驱动的测试行为转化为机器执行的过程
自动化测试分类
接口自动化测试
接口自动化测试其实就是API测试,相对于UI自动化API自动化更加容易实现,执行起来也更稳定
特点
1、可在产品前期,接口完成后介入;
2、用力维护量小;
3、适合接口变动较小,界面变动频繁的项目
常见的测试工具有:RobotFramework,Postman,JMeter等等
UI自动化测试
UI层的自动化测试更加贴近用户的需求和软件系统的实际业务
特点
1、用例维护量大;
2、页面相关性强,必须后期项目页面开发完成后介入;
3、UI测试适合与界面变动较小的项目
移动端自动化测试
Web端自动化测试
常见的自动化web测试工具:QTP、Selenium、RFT等等
selenium工具
优点
1、开源免费;
2、支持多浏览器,如Chrome、Firefox、IE浏览器等等
3、支持多语言
4、支持多系统,如Linux、Windows、MacOS
5、selenium包提供了很多可供测试的使用的API
selenium编写的自动化脚本是如何打开浏览器的(selenium、Driver、浏览器三者之间的关系)
1 、程序发送Selenium命令给浏览器的驱动程序(简单理解为脚本就是命令)
2 、浏览器驱动程序接收到命令后 ,驱动浏览器去执行命令
3 、浏览器驱动程序获取命令执行的结果,返回给自程序
4 、程序对返回结果进行处理
自动化示例
1、导入selenium包
2、在Java中新建包,在包中新建类
3、代码实现
创建驱动实例,创建会话;访问网站;查找元素;操作元素;结束会话
//查询网址搜索关键词边伯贤
public void baekhyunTest() throws InterruptedException {
//创建驱动实例,创建会话(打开浏览器
ChromeDriver driver = new ChromeDriver();
Thread.sleep(5000);
//在浏览器输入百度网址,访问百度首页
driver.get("https://www.baidu.com");
Thread.sleep(5000);
//找到百度首页输入框元素,并输入关键词“边伯贤”
driver.findElement(By.cssSelector("#kw")).sendKeys("边伯贤");
Thread.sleep(5000);
//找到百度首页“百度一下“按钮,并点击一下
driver.findElement(By.cssSelector("#su")).click();
Thread.sleep(5000);
//结束会话(关闭浏览器)
driver.quit();
}
Selenium常用方法
1、查找页面元素
findElement()
参数:By类(提供通过什么方式来查找元素)
返回值:webElement
findElements()
参数:By类(提供通过什么方式来查找元素)
返回值:List<webElement>
public void methodTest(){
ChromeDriver driver=new ChromeDriver();
driver.get("https://www.baidu.com");
List<WebElement> eles=driver.findElements(By.className("hotsearch-item"));
for(WebElement ele:eles){
System.out.println(ele.getText());
}
}
2、元素的定位 By类
selector(基础选择器、复合选择器)
功能:选中页面中指定的标签元素
//元素的定位
//选择器selector
driver.findElement(By.cssSelector(“kw”));
xpath
语法:
层级:/子级 //跳级
属性:@
函数:contains()......
自动化要求元素的定位必须要唯一。但是手动在页面复制selector或者xpath元素不一定是唯一的,需要我们进行手动修改到唯一
3、常见的元素操作
对元素操作的前提:能够找到元素
3.1、输入文本
sendKeys
仅适用于文本字段和内容可编辑的元素
WebElement ele=driver.findElement(By.cssSelector("#kw"));
ele.sendKeys("baekhyun yyds!");
driver.findElement(By.cssSelector("#kw")).sendKeys("baekhyun yyds");
3.2、点击click
driver.findElement(By.cssSelector("#su")).click();
案例:博客系统的自动登录
public void TestBlogLogin() throws InterruptedException {
driver.get("http://101.42.46.10:8080/blogSystem/login.html");
Thread.sleep(3000);
driver.findElement(By.cssSelector("#username")).sendKeys("啵啵");
driver.findElement(By.cssSelector("#password")).sendKeys("123");
driver.findElement(By.cssSelector("#login-btn")).click();
Thread.sleep(3000);
driver.quit();
}
3.3、提交 submit(通过回车键提交)
仅适用于表单元素
driver.findElement(By.cssSelector("#su")).submit();
3.4、清除 clear
driver.findElement(By.cssSelector("#kw")).sendKeys("baekhyun yyds");
Thread.sleep(2000);
driver.findElement(By.cssSelector("#kw")).clear();
driver.findElement(By.cssSelector("#kw")).sendKeys("baekhyun");
driver.findElement(By.cssSelector("#su")).click();
3.5、获取文本 getText()
获取属性的值getAttribute()
String text=driver.findElement(By.cssSelector("#hotsearch-content-wrapper > li:nth-child(2) > a > span.title-content-title")).getText();
System.out.println("获取到的文本:"+text);
3.6、获取页面的标题和URL
System.out.println(driver.getTitle());
System.out.println(driver.getCurrentUrl());
4、窗口
4.1、窗口大小的设置:最大化、最小化、全屏窗口、手动设置窗口大小
//窗口最大化
driver.manage().window().maximize();
Thread.sleep(3000);
//窗口最小化
driver.manage().window().minimize();
Thread.sleep(3000);
//全屏
driver.manage().window().fullscreen();
Thread.sleep(3000);
//手动设置窗口大小
driver.manage().window().setSize(new Dimension(1024,512));
Thread.sleep(3000);
4.2、窗口的切换
打开百度首页,点击图片超链接进入到百度图片首页,获取百度图片页面的“百度一下”按钮
当浏览器每次打开一个标签页的时候,会自动地给每个标签页进行标识
driver.findElement(By.cssSelector("#s-top-left > a:nth-child(6)")).click();
//
String curhandel=driver.getWindowHandle();
System.out.println(curhandel);
//先获取所有标签的句柄
Set<String> handels=driver.getWindowHandles();
for (String handel:handels){
if (handel!=curhandel){
driver.switchTo().window(handel);
}
}
Thread.sleep(3000);
driver.findElement(By.cssSelector("#homeSearchForm > span.s_btn_wr > input")).click();
4.3、屏幕截图
首先保存屏幕截图文件需要用到的包
<!--保存屏幕截图文件所要用到的包 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>1.4</version>
</dependency>
driver.findElement(By.cssSelector("#kw")).sendKeys("边伯贤");
driver.findElement(By.cssSelector("#su")).click();
Thread.sleep(3000);
//屏幕截图(保存现场)
File srcfile=driver.getScreenshotAs(OutputType.FILE);
//把屏幕截图好的文件放到指定的路径下
String filename="my.png";
FileUtils.copyFile(srcfile,new File(filename));
driver.findElement(By.cssSelector("#\\31 > div > div > div > div > div.cos-row.row-text_Johh7.row_5y9Az
当程序执行时,我们需要在代码里添加等待机制
5、等待
强制等待、隐式等待、显示等待、流畅等待
5.1、强制等待
程序阻塞进行 Thread.sleep()
5.2、隐式等待
会作用于driver的整个生命周期,隐式等待会一直轮询判断元素是否存在,如果不存在就在等待好的时间里不断地进行轮询,直到元素能够被找到
void implicitlyWait(){
//添加隐式等待
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));
driver.get("https://www.baidu.com");
driver.findElement(By.cssSelector("#kw")).sendKeys("都暻秀");
driver.findElement(By.cssSelector("#su")).click();
driver.findElement(By.cssSelector("#\\31 > div > div > div > div > div.cos-row.row-text_Johh7.row_5y9Az > div > a > div > p > span > span"));
driver.quit();
}
5.3、显示等待
WebDriverWait(WebDirver,Duration)
void webDriverWait(){
driver.get("https://www.baidu.com");
driver.findElement(By.cssSelector("#kw")).sendKeys("都暻秀");
driver.findElement(By.cssSelector("#su")).click();
//显示等待
new WebDriverWait(driver,Duration.ofSeconds(5)).until(driver->driver.findElement(By.cssSelector("#\\31 > div > div > div > div > div.cos-row.row-text_Johh7.row_5y9Az > div > a > div > p > span > span")));
driver.quit();
}
6、浏览器导航
浏览器的前进、后退、刷新
void navigateControl() throws InterruptedException {
//driver.get("https://www.baidu.com");
driver.navigate().to("https://www.baidu.com");
Thread.sleep(3000);
//想要回退到访问百度网址之前的状态
driver.navigate().back();
Thread.sleep(3000);
//前进,又进入到了百度首页
driver.navigate().forward();
Thread.sleep(3000);
//刷新百度首页
driver.navigate().refresh();
Thread.sleep(3000);
driver.quit();
}
7、弹窗
弹窗的类型:警告弹窗、确认弹窗、提示弹窗
处理弹窗的步骤:
1、将driver对象作用到弹窗上(切换到弹窗);
dirver.switchTo.alert()
2、选择确认或取消(提示弹窗输入文本)
void AlertControl(){
//弹窗
//get参数为url,而不是文件路径
//在本地打开html文件之后,需要复制浏览器里的链接放到get里,而不是复制html本地的文件路径
driver.get("xxx");
//打开弹窗
driver.findElement(By.cssSelector("xxx")).click();
//切换到弹窗进行弹窗的处理
Alert alert=driver.switchTo().alert();
//1、点击确认
alert.accept();
//2、点击取消
alert.dismiss();
//3、输入关键词
alert.sendKeys("xxx");
driver.quit();
}
警告弹窗只有确认按钮,但是accept和dismiss都能处理;
警告弹窗和确认弹窗都没有输入文本的地方,但是如果要执行alert.sendKeys代码也不会报错
8、选择框
选项的选择方式:1、根据文本来选择;2、根据属性框来选择;3、根据序号来选择
void selectControl() throws InterruptedException {
//选择框
driver.get("xxx");
Thread.sleep(3000);
WebElement ele=driver.findElement(By.cssSelector("xxx"));
//先创建选择框对象
Select select=new Select(ele);
Thread.sleep(3000);
//根据文本来选择
select.selectByVisibleText("");
//根据属性值来选择
select.selectByValue("");
//根据序号来选择
select.selectByIndex(x);
Thread.sleep(3000);
driver.quit();
}
9、执行脚本
executeScript()其中的参数是js代码
void scriptControl() throws InterruptedException {
//执行脚本
driver.get("https://image.baidu.com/");
Thread.sleep(3000);
//执行js命令:让页面置顶/置底
driver.executeScript("document.documentElement.scrollTop=300");
Thread.sleep(300);
driver.executeScript("document.documentElement.scrollTop=0");
Thread.sleep(300);
driver.quit();
}
driver.get("https://www.baidu.com");
Thread.sleep(3000);
driver.executeScript("var d=document.querySelector('#kw');d.value='边伯贤'");
Thread.sleep(3000);
driver.quit();
10、文件的上传
sendKeys(“文件路径+文件”)
void fileUploadControl() throws InterruptedException {
driver.get("xxx");
Thread.sleep(3000);
driver.findElement(By.cssSelector("xxx")).sendKeys("文件路径+文件");
Thread.sleep(3000);
driver.quit();
}
11、浏览器参数的设置
实际在工作中,测试人员将自动化部署在机器上自动地执行,测试人员不会关注过程,而是直接查看自动化执行的结果
无头模式
void paramControl(){
//百度搜索边伯贤
//先创建选项对象,在设置浏览器参数
ChromeOptions options=new ChromeOptions();
options.addArguments("-headless");
ChromeDriver driver=new ChromeDriver(options);
driver.get("https://www.baidu.com");
driver.findElement(By.cssSelector("#kw")).sendKeys("边伯贤");
driver.findElement(By.cssSelector("#su")).click();
driver.quit();
}
浏览器的参数设置需要在创建浏览器对象之前
junit
junit是Java的单元测试工具,我们在实现自动化的时候需要借助一下junit库里面提供的一些方法
1、注解
@Test
表示方法是测试方法,执行当前这个类时,会自动的执行该类下所有带@Test注解的用例
@BeforeEach
表示当前的方法需要在每个用例执行之前都执行一次
@BeforeAll
表示当前的方法需要在当前类下所有用例之前执行一次,被该注解修饰的方法必须为静态方法
@AfterEach
表示当前的方法需要在每个用例执行之后都执行一次
@AfterAll
表示当前的方法需要在当前类下所有用例之后执行一次,被该注解修饰的方法必须为静态方法
public class junitTest {
// @BeforeEach
// void baseAnnotate(){
// System.out.println("beakhyun");
// }
// @BeforeAll
// static void cy(){
// System.out.println("chanyeol");
// }
// @AfterEach
// void baseAnnotate(){
// System.out.println("beakhyun");
// }
@AfterAll
static void cy(){
System.out.println("chanyeol");
}
@Test
void dd(){
System.out.println("do");
}
@Test
void sh(){
System.out.println("sehun");
}
}
2、断言 Assertions类
断言匹配/不匹配
assertEquals/assertNotEquals
@Test
void assertTest(){
ChromeDriver driver=new ChromeDriver();
driver.get("https://www.baidu.com");
String text=driver.findElement(By.cssSelector("#su")).getAttribute("value");
System.out.println(text);
//Assertions.assertEquals("百度两下",text);
Assertions.assertNotEquals("百度两下",text);
driver.quit();
}
断言为真/断言为假
assertTrue/assertFalse
@Test
void assertTest1(){
//Assertions.assertTrue(4==12);
Assertions.assertFalse(4==12);
}
断言结果为空/不为空
assertNull/assertNotNull
@Test
void assertTest2(){
//Assertions.assertNull("beakhyun");
Assertions.assertNotNull("beakhyun");
}
3、用例的执行顺序
测试用例的执行与编写测试用例的顺序无关
3.1、通过order注解来排序
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class junitTest {
@Test
@Order(2)
void loginTest(){
System.out.println("loginTest");
}
@Test
@Order(3)
void indexTest(){
System.out.println("indexTest");
}
@Test
@Order(1)
void editTest(){
System.out.println("editTest");
}
}
先要使用注解说明当前类下所有的用例需要使用order注解来进行排序(注意:该注解必须使用到类上);然后通过order来指定用例的具体顺序
4、参数化
尽可能的通过一个用例,多组参数来模拟用户的行为
在使用参数化注解之前需要声明该方法为参数化方法 @ParameterizedTest
4.1、单参数
要通过注解提供数据来源
@ParameterizedTest
@ValueSource(strings={"beakhyun","do","sehun"})
void SparamsTest(String name){
System.out.println(name);
}
@ValueSource(数据类型方法={参数1,参数2,参数3...})
4.2、多参数
从注解里手动编写数据源(每个双引号就是一组参数/测试用例)
@ParameterizedTest
@CsvSource({"baekhyun,30","do,29","sehun,28"})
void muchParamsTest(String name,int age){
System.out.println("name:"+name+",age:"+age);
}
从第三方csv文件读取数据源
@ParameterizedTest
@CsvFileSource(files="C:\\Users\\admin\\Desktop\\mycsv.csv")
void csvfileParamsTest(String name,int age){
System.out.println("name:"+name+",age:"+age);
}
4.3、动态参数
如果要返回的数据类型不统一,就需要使用组合类型Arguments
@ParameterizedTest
@MethodSource("methodParams")
void dynamicmethodParmsTest(String name,int age){
System.out.println("name:"+name+",age:"+age);
}
static Stream<Arguments> methodParams() throws InterruptedException {
//构造动态参数
String[] arr=new String[5];
for (int i=0;i<arr.length;i++){
Thread.sleep(500);
arr[i]=System.currentTimeMillis()+"";
}
return Stream.of(
Arguments.arguments(arr[0],20),
Arguments.arguments(arr[1],20),
Arguments.arguments(arr[2],20),
Arguments.arguments(arr[3],20),
Arguments.arguments(arr[4],20)
);
}
使用了参数化注解的方法不能再使用@Test注解(@Test只能作用到非参数化的用例上)
5、测试套件
先创建一个类,通过@Suite注解标识该类为测试套件类(而不是测试类)
@Suite
public class runSuite {
}
5.1、指定类来运行用例
@Suite
@SelectClasses({aaa.class,bbb.class})
public class runSuite {
}
想要运行的用例必须被@Test注解(除参数化的用例外)
5.2、指定包名来运行包下的所有用例
@Suite
@SelectPackages("com.autotest0212")
public class runSuite {
}