软件测试之自动化测试
目录
1.什么是自动化测试
将人工测试手段转换为机器执行的过程
自动化测试金字塔
自动化测试分类:
单元测试:
最大的投入应该在单元测试上,单元测试运行的频率也更加高。java的单元测试框架是Junit
接口测试:
接口测试就是API测试,相对于UI自动化API自动化更加容易实现,执行起来也更稳定。
接口自动化的有以下特点:
可在产品前期,接口完成后介入
用例维护量小
适合接口变动较小,界面变动频繁的项目
常见的接口自动化测试工具有,RobotFramework,JMeter,SoapUI,TestNG+HttpClient,Postman等。
UI测试:
虽然测试金字塔告诉我们尽量多做API层的自动化测试,但是UI层的自动化测试更加贴近用户的需求和软件系统的实际业务。并且有时候我们不得不进行UI层的测试。
UI自动化的特点:
用例维护量大
页面相关性强,必须后期项目页面开发完成后介入
UI测试适合与界面变动较小的项目
selenium介绍
什么是selenium?
是web应用中基于UI的自动化测试框架
特点
支持多平台、多浏览器、多语言
原理
三个对象:
自动化脚本代码:编写的代码
浏览器驱动:需要下载驱动
浏览器:各种浏览器
2.selenium+java环境搭建
1.安装chrome浏览器并察看其版本
2.下载浏览器驱动,要和对应的版本相同的驱动
3.将驱动放在浏览器应用目录下,并且配置Path环境
4.验证是否搭建好环境
导入依赖文件
<dependencies>
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
</dependencies>
编写代码
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
public class Main {
public static void main(String[] args) {
ChromeOptions options = new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
WebDriver webDriver = new ChromeDriver(options);
webDriver.get("https://www.baidu.com");
}
}
至此环境搭建成功
此时打开chromedriver.exe
3.熟悉selenium的API
定位元素
模拟点击对象:click
清除对象输入的文本:clear
提交 :submit(如果在form标签中,和click效果相同。非form标签中使用会报错!)
获取元素文本信息:text
获取元素属性值:getAttribute
定位方式1:
定位方式2:
启动成功
css选择语法:
css语法选择器
id选择器:#id值
类选择器:.类名
标签选择器:标签名
后代选择器:父级选择器,子级选择器
xpath:
绝对路径:/开头,效率比较低,不常用 /html/head/title
相对路径://开头 经常用到
相对路径+索引://form/span[1]/input
相对路径+属性值://input[@class="s_ipt"]
相对路径+通配符://*[@*="su"]
相对路径+文本匹配://a[text()="新闻"]
getAttribute的使用
获取"百度一下"
private static void test(){
ChromeOptions options = new ChromeOptions();
//参数意义:允许所有的请求
options.addArguments("--remote-allow-origins=*");
WebDriver webDriver = new ChromeDriver(options);
//打开百度首页
webDriver.get("https://www.baidu.com");
String button_value = webDriver.findElement(By.cssSelector("#su")).getAttribute("value");
if (button_value.equals("百度一下")){
System.out.println("测试通过");
}else{
System.out.println(button_value);
System.out.println("测试不通过");
}
}
添加等待
1.sleep休眠
引入time包,就可以在脚本中添加休眠时间了,固定性休眠
2.隐式等待
隐式等待是在整个测试脚本的执行过程中设置一个默认的等待时间。当查找元素时,如果元素未立即可用,则会等待一段预定的时间,直到元素可见或超过最大等待时间为止。不需要在代码中显式指定等待条件。
假设等待三天时间:
sleep会持续等待固定时间
隐式地等待并非一个固定的等待时间,当脚本执行到某个元素定位时,如果元素可以定位,则继续执行;如果元素定位不到,则它以轮询的方式不断的判断元素是否被定位到。直到超出设置的时长
对比
private static void test2() throws InterruptedException {
ChromeOptions options = new ChromeOptions();
//参数意义:允许所有的请求
options.addArguments("--remote-allow-origins=*");
WebDriver webDriver = new ChromeDriver(options);
//打开百度首页
webDriver.get("https://www.baidu.com");
//等待3s
sleep(3000);
//找到输入框并输入java
webDriver.findElement(By.cssSelector("#kw")).sendKeys("java");
//获取提交按钮并且提交
webDriver.findElement(By.cssSelector("#su")).submit();
//进行隐式等待
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.DAYS);
//清空
webDriver.findElement(By.cssSelector("#kw")).clear();
}
运行程序,等待3s后,立即输入java并且清空了。
3.显示等待
显示等待是在代码中明确地指定等待条件并设置等待时间。测试脚本会在特定条件满足或超过最大等待时间之前一直等待。常见的等待条件包括元素可见、元素可点击、元素存在等。具体的等待时间需要根据系统响应时间而定。如果等待条件在超过最大等待时间后仍未满足,会抛出异常。
//显示等待API使用
private static void test4() {
ChromeOptions options = new ChromeOptions();
//参数意义:允许所有的请求
options.addArguments("--remote-allow-origins=*");
WebDriver webDriver = new ChromeDriver(options);
//打开百度首页
webDriver.get("https://www.baidu.com");
//判断元素是否可以被点击
WebDriverWait wait = new WebDriverWait(webDriver,3000);
wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#bottom_layer > div > p:nth-child(7) > a")));
}
执行后说明可以点击,如果出现定位不到的信息,就会报错
显示等待和隐式等待的区别:
隐式等待:当前页面的所有元素都加载了后才进行向下执行
显示等待:只针对确定的条件进行等待,所有元素是否加载不影响
打印信息
打印title和url
private static void test3() {
ChromeOptions options = new ChromeOptions();
//参数意义:允许所有的请求
options.addArguments("--remote-allow-origins=*");
WebDriver webDriver = new ChromeDriver(options);
//打开百度首页
webDriver.get("https://www.baidu.com");
String url = webDriver.getCurrentUrl();
String title = webDriver.getTitle();
if (url.equals("https://www.baidu.com/") && title.equals("百度一下,你就知道")){
System.out.println("url: "+url);
System.out.println("title: "+title);
System.out.println("测试通过");
}else {
System.out.println("测试不通过");
}
}
浏览器的相关操作
1.浏览器前进
2.浏览器后退
private static void test5() throws InterruptedException {
ChromeOptions options = new ChromeOptions();
//参数意义:允许所有的请求
options.addArguments("--remote-allow-origins=*");
WebDriver webDriver = new ChromeDriver(options);
//打开百度首页
webDriver.get("https://www.baidu.com");
//搜索后强制等待3s
webDriver.findElement(By.cssSelector("#kw")).sendKeys("hello");
webDriver.findElement(By.cssSelector("#su")).submit();
sleep(3000);
//浏览器后退
webDriver.navigate().back();
//等待3s
webDriver.navigate().refresh();
sleep(3000);
//浏览器前进
webDriver.navigate().forward();
}
搜索后休眠,然后后退、刷新、前进到搜索hello页面
3.浏览器滚动条操作
private static void test5() throws InterruptedException {
ChromeOptions options = new ChromeOptions();
//参数意义:允许所有的请求
options.addArguments("--remote-allow-origins=*");
WebDriver webDriver = new ChromeDriver(options);
//打开百度首页
webDriver.get("https://www.baidu.com");
//搜索后强制等待3s
webDriver.findElement(By.cssSelector("#kw")).sendKeys("hello");
webDriver.findElement(By.cssSelector("#su")).submit();
sleep(3000);
//浏览器后退
webDriver.navigate().back();
//等待3s
webDriver.navigate().refresh();
sleep(3000);
//浏览器前进
webDriver.navigate().forward();
//滚动条
((JavascriptExecutor)webDriver).executeScript("document.documentElement.scrollTop=10000");
}
//设置最浏览器为最大尺寸
webDriver.manage().window().maximize();
sleep(3000);
//设置满屏
webDriver.manage().window().fullscreen();
sleep(3000);
//高1000宽600
webDriver.manage().window().setSize(new Dimension(600,1000));
键盘组合键用法
private static void test8() throws InterruptedException {
ChromeOptions options = new ChromeOptions();
//参数意义:允许所有的请求
options.addArguments("--remote-allow-origins=*");
WebDriver webDriver = new ChromeDriver(options);
//打开百度首页
webDriver.get("https://www.baidu.com");
//搜索后强制等待3s
webDriver.findElement(By.cssSelector("#kw")).sendKeys("hello");
//CONTROL+A
webDriver.findElement(By.cssSelector("kw")).sendKeys(Keys.CONTROL,"A");
sleep(3000);
//CONTROL+X
webDriver.findElement(By.cssSelector("kw")).sendKeys(Keys.CONTROL,"X");
sleep(3000);
//CONTROL+V
webDriver.findElement(By.cssSelector("kw")).sendKeys(Keys.CONTROL,"V");
sleep(3000);
}
sendKeys(Keys.CONTROL,"A"):全选 sendKeys(Keys.CONTROL,"C"):复制 sendKeys(Keys.CONTROL,"V"):粘贴 sendKeys(Keys.CONTROL,"X"):剪切
鼠标事件
perform():执行所有存储的行为 contextClick():右击 doubleClick():双击 moveToElement():移动
private static void test9() throws InterruptedException {
ChromeOptions options = new ChromeOptions();
//参数意义:允许所有的请求
options.addArguments("--remote-allow-origins=*");
WebDriver webDriver = new ChromeDriver(options);
//打开百度首页
webDriver.get("https://www.baidu.com");
webDriver.findElement(By.cssSelector("#kw")).sendKeys("hello");
webDriver.findElement(By.cssSelector("#su")).click();
sleep(3000);
//找到图片按钮
WebElement webElement = webDriver.findElement(By.cssSelector("#s_tab > div > a.s-tab-item.s-tab-item_1CwH-.s-tab-pic_p4Uej.s-tab-pic"));
//鼠标右击
Actions actions = new Actions(webDriver);
sleep(3000);
actions.moveToElement(webElement).contextClick().perform();
}
输入hello,然后将鼠标移动到图片上,并点击右键
特殊场景
定位一组元素
webdriver 可以很方便的使用findElement 方法来定位某个特定的对象,不过有时候我们却需要定位一组对象,这时候就需要使用findElements 方法。
定位一组对象一般用于以下场景:
批量操作对象,比如将页面上所有的checkbox 都勾上
先获取一组对象,再在这组对象中过滤出需要具体定位的一些对象。比如定位出页面上所有的checkbox,然后选择最后一个
get_attribute:获得属性值
实现自动选中所有复选框,就是定位一组元素
使用input标签定位一组元素,然后遍历 ,是checkbox就勾选,否则不做处理
private static void page1() {
ChromeOptions options = new ChromeOptions();
//参数意义:允许所有的请求
options.addArguments("--remote-allow-origins=*");
WebDriver webDriver = new ChromeDriver(options);
webDriver.get("file:///D:/IDEA2021/test-class106-107-master/code/_20230512testcode/src/main/Page/test01.html");
//获取所有input框
List<WebElement> elements = webDriver.findElements(By.cssSelector("input"));
//遍历
//getAttribute是获取属性的值,type就是元素的类型
for (int i = 0; i < elements.size(); i++) {
if(elements.get(i).getAttribute("type").equals("checkbox")){
elements.get(i).click();
}
}
}
getAttribute是获取属性的值,type就是元素的类型
运行后:
多层框架定位
对于一个web 应用,经常会出现框架(frame)或窗口(window)的应用,这也就给我们的定位带来了一定的困难
定位一个frame :switch_to.frame(name_or_id_or_frame_element)
定位一个窗口window:switch_to.window(name_or_id_or_frame_element)
多层框架的定位
switch_to.frame(name_or_id_or_frame_element):通过frame的id或者name或者frame自带的其它属性来定位框架,这里switch_to.frame()把当前定位的主体切换了frame里。switch_to.default_content:从frame中嵌入的页面里跳出,跳回到最外面的默认页面中。
实现自动点击click
可见看到herf是在iframe中的,不能直接用选择器获取然后操作
switch_to.frame
点击成功
下拉框处理
下拉框是我们最常见的一种页面元素,对于一般的元素,我们只需要一次就定位,但下拉框里的内容需要进行两次定位,先定位到下拉框对下拉框进行操作后,再定位到下拉框内里的选项。
和之前的操作有所不同,首先要定位到下拉框的元素,然后选择下拉列表中的选项进行点击操作。
private static void page3() {
WebDriver webDriver = new ChromeDriver();
webDriver.get("file:///D:/IDEA2021/test-class106-107-master/code/_20230512testcode/src/main/Page/test03.html");
WebElement webElement = webDriver.findElement(By.cssSelector("#ShippingMethod"));
Select select = new Select(webElement);
select.selectByIndex(3);//从0开始的
}
弹窗处理
alert、confirm、prompt 的处理
text 返回alert/confirm/prompt 中的文字信息
accept 点击确认按钮
dismiss 点击取消按钮,如果有的话
send_keys 输入值,如果alert 没有对话框就不能用了,不然会报错
private static void page4() throws InterruptedException {
WebDriver webDriver = new ChromeDriver();
webDriver.get("file:///D:/IDEA2021/test-class106-107-master/code/_20230512testcode/src/main/Page/test04.html");
webDriver.findElement(By.cssSelector("button")).click();
sleep(3000);
//取消弹窗,alert
webDriver.switchTo().alert().dismiss();
sleep(3000);//点击按钮
webDriver.findElement(By.cssSelector("button")).click();
//输入hello
webDriver.switchTo().alert().sendKeys("hello");
sleep(3000);//确认
webDriver.switchTo().alert().accept();
}
上传文件
文件上传操作也比较常见功能之一,上传功能没有用到新有方法或函数,关键是思路。
上传过程一般要打开一个本地窗口,从窗口选择本地文件添加。所以,一般会卡在如何操作本地窗口添加上传文件。其实,在selenium webdriver 没我们想的那么复杂;只要定位上传按钮,通过send_keys 添加本地文件路径就可以了。绝对路径和相对路径都可以,关键是上传的文件存在。
private static void page5() {
WebDriver webDriver = new ChromeDriver();
webDriver.get("file:///D:/IDEA2021/test-class106-107-master/code/_20230512testcode/src/main/Page/test05.html");
webDriver.findElement(By.cssSelector("input")).sendKeys("C:\\ProgramData\\historyDown.xml");
}
关闭浏览器
面试题:quit与close区别:
quit关闭浏览器,close仅关闭当前 的页面(原始页面,get获取的页面)
quit会清空缓存,close不会清空缓存
private static void test10() throws InterruptedException {
WebDriver webDriver = new ChromeDriver();
webDriver.get("https://www.baidu.com");
webDriver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)")).click();
sleep(4000);
webDriver.quit();
webDriver.close();
}
窗口切换
打开百度,点击新闻,输入
需要进行页面的切换,否则找不到元素,元素默认是在get打开的页面找元素
private static void test11() throws InterruptedException {
WebDriver webDriver = new ChromeDriver();
webDriver.get("https://www.baidu.com");
webDriver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)")).click();
sleep(4000);
webDriver.findElement(By.cssSelector("#ww")).sendKeys("新闻联播");
webDriver.findElement(By.cssSelector("#s_btn_wr")).click();
}
没进行页面切换就会报错,找不到跳转的页面的元素
进行页面句柄的寻找以及窗口的切换
private static void test11() throws InterruptedException {
WebDriver webDriver = new ChromeDriver();
webDriver.get("https://www.baidu.com");
webDriver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)")).click();
sleep(4000);
System.out.println(webDriver.getWindowHandle());//获取get后打开的窗口句柄,~s是获取所有页面的窗口句柄
Set<String> handles = webDriver.getWindowHandles();
String target_handle = "";
//将最后一个页面的句柄找出来,防止会定位到其他页面相同的元素
for (String handle:handles) {
target_handle = handle;
}
//切换窗口
webDriver.switchTo().window(target_handle);
sleep(3000);
webDriver.findElement(By.cssSelector("#ww")).sendKeys("新闻联播");
webDriver.findElement(By.cssSelector("#s_btn_wr")).click();
}
截图
先导入依赖
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
打开百度,输入测试,然后截图
private static void test12() throws InterruptedException, IOException {
WebDriver webDriver = new ChromeDriver();
webDriver.get("https://www.baidu.com");
webDriver.findElement(By.cssSelector("#kw")).sendKeys("测试");
webDriver.findElement(By.cssSelector("#su")).click();
sleep(3000);
//进行截图
//类型是文件,此时存储在内存
File file = ((TakesScreenshot)webDriver).getScreenshotAs(OutputType.FILE);
//存储到硬盘中
FileUtils.copyFile(file,new File("C://Users//User//Documents//2023.png"));
}