测试:
这里写目录标题
基础概念:
-
什么是需求
-
用户需求: 简单可以理解为甲方的需求,程序员需要完成的用户需求
-
软件需求: 也就是功能需求,该需求会详细描述开发人员需要实现的功能.
软件需求是测试人员进行测试的基本依据.
测试人员根据软件需求文档来设计测试用例
用户需求不能作为开发和测试的基本依据,因为用户需求不一定合理,需要将用户需求转为软件需求
-
-
什么是测试用例:
测试人员在执行之前需要编写测试用例.测试用例的好怀与产品的测试质量有很大的关联关系.
测试用例是实施测试而向测试的系统提供的一组集合,这组集合包括
-
测试环境.
-
测试步骤.
-
测试数据.
-
预期结果.
现在测试用例都是使用思维导图的方式来编写
-
-
什么是BUG
也就是软件错误:当且仅当规格说明是存在的并且正确,程序与规格说明之间的不匹配才是错误。当需求规格说明书没有提到的功能,判断标准以最终用户为准:当程序没有实现其最终用户合理预期的功能要求时,就是软件错误。
也就是功能不符合软件需求说明书或者需求说明书没有说明.但是功能不符合用户需求功能的就是软件错误也就是BUG.
-
开发模型:
就是开发流程或者项目的推进流程(软件的生命周期)
-
需求分析.(需求是否合理)
-
计划,(什么时候开始,整个流程多久,什么时候结束)
-
设计(将需求细化,进行技术设计(使用什么框架,设计哪些接口,采用什么技术))
-
编码(参照需求文档编码)
-
测试 (编写测试用例并根据测试用例进行测试)
-
运行与维护
瀑布模型:
线性结构: 意味着前一个阶段结束后下一个阶段才能开始.可能会导致风险在后期的测试阶段才暴露,失去提前纠正的机会.
螺旋模型:
在瀑布模型的基础上增加了风险分析,测试随着开发的迭代而迭代
增量模型:
将项目进行模块化,使得每个模块能够进行独立开发与测试.
迭代模型:
迭代模型会先完成基础功能的版本,再经历一起一起的迭代优化,慢慢完善.
敏捷模型:
不重视开发的流程,重视开发的效率.
- 敏捷宣言:
-
强调团队内部人员尽可能的进行高效的沟通,
-
敏捷模型最终的标准就是可交付的软件
-
敏捷宣言的特点: 轻流程, 轻文档, 重目标, 重产出
敏捷模型scrum:
每个迭代周期为1 - 4 周, 一般为一周
了解三个重要的角色和五个重要会议:
三个重要角色:
-
-
产品经理
-
项目经理
-
研发团队
五个重要会议:
-
需求发布会议 : 确定本次迭代要实现的需求
-
迭代计划会议 : 明确需求拆分成一个个任务,明确每个任务对应的责任人.初步评估工时.
-
每日会议: 研发团员需要回答三个问题: 昨天做了什么,今天要做什么.遇到了什么问题.每日会议结束之后的产物就是可交付的软件
-
演示会议: 每日会议结束之后的产物: 用户的需求
-
回顾会议: 回顾之前开发的可取点以及需要改进点
-
测试流程.
-
需求分析
-
测试计划
-
测试设计与开发
-
执行测试
-
测试评估
测试V模型:
明确测试有不同的类型 而且每个类型与前期开发工作之前的队友关系
缺陷就是测试后置
测试W模型:
测试与开发是同步进行的.能够全面,尽快地发现问题.
开发和测试虽然是同步的,但是仍然存在前后关系.
-
BUG:
创建一个合理的bug:
创建bug的目标是为了能够让其他人尝试复现.
创建bug的要素:
-
问题的版本
-
发现问题的环境
-
发现问题的步骤
-
预期结果
-
实际结果
bug 的级别:
-
崩溃 : 一般是系统崩溃,死机,数据库数据丢失等.
-
严重 : 主要功能丧失,用户数据丢失,功能设计与需求严重不符等.
-
一般 : 功能没有完全实现但是不影响使用,查询时间长等.
-
次要 : 功能已经实现,但是界面或者性能缺陷,一般是建议优化类问题.
bug的什么周期:
-
new: 新发现的bug.
-
open: 确认是bug,并且认为需要进行修改
-
Rejected: 认为不是bug,拒绝修改
-
delay: 延迟修改.
-
fixed: 立即修改.
-
closed: 认为bug已经修改并且验证成功, bug关闭
-
reopen: 验证失败,需要重新修改.
跟开发争执如何解决:
-
检查自身,检查bug是否描述不清楚
-
对于等级低的bug,要劝说开发站在用户的角度考虑问题
-
BUG的定级要有理有据.
-
不光能提出bug,最好也能提出解决方案.
-
组织bug评审: 邀请代表参加(产品代表,开发代表,测试代表等)
bug评审会议要解决以下问题:
-
如何修改bug
-
如何避免类似的问题发生
-
-
对事不对人.
测试用例:
编写测试用例的万能公式:
功能测试+性能测试+界面测试+兼容性测试+易用性测试+安全测试
-
功能测试: 对产品的功能设计测试用例 (来源是需求文档 / 日常经验)
-
性能测试: 功能没有问题不代表性能好.所以需要进行性能的测试
-
界面测试: 大小,颜色,材质,形状等等
-
兼容性测试: 软件的不同版本是否兼容.不同的系统版本,不同浏览器,数据兼容性等.
-
易用性测试: 产品是否具备简单易上手的属性,
-
安全测试: 用户的隐私数据是否加密,SQL注入,越权问题
案例: 登录功能的测试:
设计测试用例的方法:
-
等价类:
也就是当我们需要测试的数据特别多时,我们可以将测试数据分为两个等价类: 有效等价类和无效等价类, 有效等价类中是针对需求文档有意义的测试数据,无效等价类是针对需求文档无意义的测试数据,从有效等价类和无效等价类中选出一个测试用例作为代表,如果这个测试用例正确,则认为等价类中的测试用例都正确.
例如密码的测试: 要求为6 - 18位:
有效等价类 : 6-18位 (代表 10位)
无效等价类 : 小于6位 ( 代表 1 位) 大于18位(代表 20 位)
-
边界值: 依据边界值测试.
同样以密码的测试为例:
有效边界: 6 和 18
无效边界: 5 和 19
-
判定表(因果图)
使用场景: 输入条件的组合对应不同的结果
判定表设计测试用例的步骤:
-
确认输入条件和输出条件
-
找出输入条件和输出条件之间的关系
-
画判定表
-
根据判定表编写测试用例
案例:
判定表:
根据判定表编写测试用例:
-
-
场景设计法:
分为基本事件流和备选事件流
以ATM取钱为例: 先设计基本事件流和备选事件流,再根据事件流编写测试用例.
如何确定边界值:
-
正交法:
allpairs
案例: 测试:
-
找出因素数和水平数
-
使用allparis生成正交表
命令为: allpairs.exe 0109.txt>0109jg.txt
-
根据正交表编写测试用例:
-
补充重要的测试用例:
如何使用allparis生成正交表
-
-
错误猜测法:
依赖个人经验来编写测试用例.
进阶篇(主要介绍测试方法):
-
可靠性测试:
可靠性 = 正常运行时间 / ( 正常运行时间+ 非正常运行时间 )
可靠性指标一般要达到4个9或者5个9(99.99% 99.999% )
如何进行可靠性测试:
-
容错性测试:
系统能够接受的错误,也就是虽然发生了错误但是不影响使用.
可靠性与容错性的区别:
案例: 有一架飞机,有4个引擎,其中一个引擎坏了,但是飞机能飞行,那么说明这个飞机的可靠性差,但是容错性好.
-
安装卸载测试:
测试安装卸载功能.
-
内存泄漏测试:
造成内存泄漏的常见原因:
-
分配完内存没有回收
-
程序的写法有问题,内存没有正常回收
-
使用的API函数有问题,造成内存泄漏
如何测试:
-
人工检查: 人工地查找没有回收的内存
-
自动工具: 借助测试内存泄漏的工具
-
-
弱网测试:
在网络情况不好的情况下,可能会造成客户端频繁地发送请求.
如何实施弱网测试: 借助工具模拟弱网环境 (Fiddler)
-
打开弱网设置
-
打开设置弱网的脚本
-
-
设置上行速率和下行速率
注意英文解释: 单位为多少ms消耗1KB 注意速率的换算.
速率参考:
对于B 与 b: 1B = 8b
-
黑盒测试:
纯功能测试.不关心具体怎么实现,(功能测试)
-
白盒测试:
关注程序的内部实现,(单元测试)
-
灰盒测试:
介于黑盒和白盒之间. (集成测试)
为什么灰盒测试不能取代黑盒测试和白盒测试:
灰盒测试没有白盒测试详尽,灰盒测试没有黑盒测试覆盖产品的广度大.
-
冒烟测试:
测试的第一步,评估软件,系统是否具备可测试的条件.
-
回归测试;
对于历史版本,历史功能进行测试,保证功能都是符合要求的. (借助自动化来进行回归测试)
对于自动化测试:
自动化测试是具有局限性的,只是协助测试人员进行测试的工具.
自动化测试:
自动化测试的分类:
-
接口自动化测试
-
UI自动化测试
-
移动端自动化测试
-
web端自动化测试
selenium( web 自动化测试工具 )
优点:
-
开源免费,
-
支持多浏览器,(如Chrome,Firefox,IE)
-
支持多系统(如Linux,Windows,MacOS)
-
支持多语言(如Java,Python)
-
selenium包提供了很多提供可测试使用的API
环境部署:
Chrome浏览器
Chrome驱动
selenium工具包
什么是驱动:
驱动计算机和设备工作起来.
人工测试的情况下,人手动打开浏览器,那么驱动是人力.
对于自动化来说,代码无法直接打开浏览器,这个时候就需要借助驱动程序来打开浏览器
selenium编写的脚本是如何打开浏览器的:
使用selenium实现web自动化测试实例:
import org.openqa.selenium.By;
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) throws InterruptedException {
ChromeOptions options = new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
ChromeDriver chromeDriver = new ChromeDriver(options);
Thread.sleep(5000);
chromeDriver.get("https://www.baidu.com");
Thread.sleep(5000);
chromeDriver.findElement(By.cssSelector("#kw")).sendKeys("迪丽热巴");
Thread.sleep(5000);
chromeDriver.findElement(By.cssSelector("#su")).click();
Thread.sleep(5000);
chromeDriver.quit();
}
}
注意这里,一开始并没有使用第一二句代码.出现了禁止访问403.,而加上之后就没有403禁止访问的问题了.
selenium常用方法:
常见元素操作方法:
-
查找页面元素:
findElement()
参数: By类 ( 提供通过什么方式来查找元素 )
返回值: List< webElement >
对于内容则需要遍历打印出来
-
By.cssSelector(“id”) 来查找
当元素在页面能找到,则正常退出
当元素在页面不能找到,则程序执行 报错
-
By.Xpath:
语法: 层级:/ 子级 //跳级
属性: @
函数: contains()
通过前端copy xpath就可以了
但是xpath有时候的定位不唯一,则需要手动修改,
修改实例:
-
-
输入文本 sendKeys()
找到需要输入文本的页面元素,再使用sendKeys() 传输文本
-
点击 click()
-
提交 submit() 通过回车键提交
对于submit,selenium官方更推荐使用click来完成提交.
-
清除 clear()
-
获取文本 getText() 返回值是String
并不是所有的标签都能获得到文本,例如百度一下的按钮的文本就不能通过getText获得,
这是因为"百度一下"是按钮的value属性,并不是文本.
-
获取属性的值 getAttribute()
示例:
String bottonText = driver.findElement(By.cssSelector("#su" )).getAttribute( name: "value");
-
获取URL getCurrentUrl()
-
获取标题 getTitle()
窗口:
窗口大小的设置: 最大化,最小化,全屏窗口,手动设置窗口大小.
示例:
//最大窗口
chromeDriver.manage().window().maximize();
//最小窗口
chromeDriver.manage().window().minimize();
//全屏
chromeDriver.manage().window().fullscreen();
//自定义窗口大小
chromeDriver.manage().window().setSize(new Dimension(1024,1024));
获取所有的句柄:
失败案例讲解:
-
为什么我们通过百度首页点击进入百度图片,再输入"迪丽热巴" 百度一下会失败?
这是因为我们驱动的句柄并没有发生转换,驱动依然停留在百度首页,所以我们需要转换句柄.
-
为什么通过百度首页搜索"迪丽热巴"再点击搜索,查找网页元素会显示报错: “没有这个元素”
chromeDriver.get("https://www.baidu.com"); chromeDriver.findElement(By.cssSelector("#kw")).sendKeys("迪丽热巴"); chromeDriver.findElement(By.cssSelector("#su")).click(); chromeDriver.findElement(By.cssSelector("#\\31 > div > div > div > div > div > div.cos-row.row-text_Johh7.row_5y9Az > div > div.title-wrapper_XLSiK > a > div > p > span > span")).click(); chromeDriver.quit();
这是因为页面渲染的速度远远不如代码执行的速度.所以代码查找这个元素的时候页面还没有渲染成功,所以失效.
解决方法: 当程序执行的时候我们需要在代码里添加等待机制.
等待:
-
强制等待 : 程序阻塞等待
Thread.sleep()
-
隐式等待 :
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(秒数));
//隐式等待 chromeDriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3)); chromeDriver.get("https://www.baidu.com"); chromeDriver.findElement(By.cssSelector("#kw")).sendKeys("迪丽热巴"); chromeDriver.findElement(By.cssSelector("#su")).click(); chromeDriver.findElement(By.cssSelector("#\\31 > div > div > div > div > div > div.cos-row.row-text_Johh7.row_5y9Az > div > div.title-wrapper_XLSiK > a > div > p > span > span")).click(); chromeDriver.quit();
隐式等待会作用于driver的整个生命周期 , 隐式等待会一直轮询判断元素是否存在,如果不存在就等待设置好的时间里不断的进行轮询,直到元素能够被找到
-
显式等待 :
与隐式等待不同, 这个只轮询等待这一条语句
new WebDriverWait(driver,Duration.ofSeconds(5)).until(driver->driver.findElement(By.cssSelector("#kw")));
new WebDriverWait(chromeDriver,Duration.ofSeconds(5)).until(driver->driver.findElement(By.cssSelector("#\\\\31 > div > div > div > div > div > div.cos-row.row-text_Johh7.row_5y9Az > div > div.title-wrapper_XLSiK > a > div > p > span > span")));
浏览器操作:
回退前进刷新操作:
//浏览器操作:
//后退
chromeDriver.navigate().back();
//前进
chromeDriver.navigate().forward();
//刷新
chromeDriver.navigate().refresh();
弹窗:
弹窗类型:
切换弹窗: (创建弹窗对象)
Alert alert = driver.switchTo().alert();
确认:
alert.accept();
取消:
alert.dismiss();
输入文本:
alert.sendkeys();
虽然警告弹窗只有确认按钮, 注意 accept 和 dismiss 都能够处理
虽然警告弹窗和确认弹窗都没有输入文本的地方,但是如果要执行alert.sendkeys() , 代码也不会报错, 只是没有效果.
选择框:
选项的选择方式:
-
创建选择框对象:
Select select = new Select(new WebElement);
-
根据文本选择
select.selectByVisibleText(文本内容);
-
根据属性值选择
select.selectByValue(属性值);
-
根据序号选择
select.selectByIndex(序号);
执行脚本:
执行js代码:
driver.executeScript(脚本代码);
文件的上传:
driver.findElenment(By.cssSector(元素)).sendkeys("文件路径 + 文件")
浏览器的参数设置
在实际的工作中,测试人员将自动化部署在机器上自动执行,并不会查看自动化执行的过程,而是查看自动化执行的结果.
ChromeOptions options = new ChromeOptions();
//参数
//无头模式
options.addArguments("-headless");
无头模式是指一种特殊的浏览器模式,这种模式下,浏览器并没有提供可视化用户界面(GUI)。这意味着当浏览器处于无头模式时,它不显示任何图形界面元素,如菜单、工具栏或浏览器窗口。无头模式特别适合于需要自动化访问网页或在服务器端执行的任务,如网络爬虫、数据抓取、自动化测试以及网页截图等。
Junit
junit是java的单元测试工具
注解:
-
@ Test
表示这个方法是测试方法, 执行当前这个类,会自动执行该类的所有@ Test 注解的方法
-
@ BeforeEach
当前的方法需要在每个用例之前都要执行一次
-
@ BeforeAll
当前的方法需要在用例之前执行一次
被修饰的方法必须为静态方法
-
@ AfterEach
当前的方法需要在每个用例之后都要执行一次
-
@ AfterAll
当前的方法需要在用例之后执行一次
被修饰的方法必须为静态方法
断言:
Assertions
-
assertEquals(期望值,实际值) 判断期望值与实际值是否相等
-
assertNotEquals(期望值,实际值) 判断期望值与实际值是否不相等
-
assertTrue(条件) 判断条件是否为true
-
assertFalse(条件) 判断条件是否为false
-
assertNull(值) 判断值是否为空
-
assertNotNull(值) 判断值是否不为空
用例的执行顺序:
手动控制用例的执行顺序
@ TestMethodOrder()
示例:
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class JunitTest {
@Test
@Order(1)
void loginTest() {
System.out.println("login");
}
@Test
@Order(2)
void editTest() {
System.out.println("edit");
}
@Test
@Order(3)
void AindexTest() {
System.out.println("Aindex");
}
}
参数化:
@ ParameterizedTest
单参数示例 :
@ValueSource(strings = {"lucy","mary","haitaos"})
void SparamsTest(String name){
System.out.println(name);
}
多参数示例 :
@CsvSource({"mary,20,女","lucy,25,女","bob,50,男","bob,50,男","bob,50,男","bob,50,男","bob,50,男","bob,50,男","bob,50,男","bob,50,男","bob,50,男","bob,50,男","bob,50,男","bob,50,男","bob,50,男"})
void muchParamsTest(String name,int age,String sex){
System.out.println("name:"+name+",age:"+age+",性别:"+sex);
}
使用Excel文件示例:
@ParameterizedTest
@CsvFileSource(files = "D:\\file\\other\\mycsv.csv")
void csvfileParamsTest(String name , int age){
System.out.println("name:"+name+",age:"+age);
}
//不使用系统自带的EXCEL文件就会报乱码的错误
@CsvFileSource(files = "D:\\file\\other\\aaaa.csv")
void csvWrongTest(String name,int age){
System.out.println("name:"+name+",age:"+age);
}
动态方法:
//通过动态方法来提供数据源
@MethodSource
void dynamicmethodPramsTest(String name,int age){
System.out.println("name:"+name+",age:"+age);
}
static Stream<Arguments> dynamicmethodPramsTest() 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)
);
}
测试套件
创建一个类 ,通过@ Suite 标识该类为特殊套件类,不是测试类
-
指定类来运行
类下想要运行的用例需要被@Test注解
@Suite @SelectClasses({aaaTest.class,bbbTests.class}) public class runSuite { }
-
指定包来运行
对于使用包名来指定的运行范围,那么该包下的所有的测试类的命名需要以Test/Tests结尾
@Suite @SelectPackages("com.autoTest0212“) public class runSuite { }
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)
);
}
#### 测试套件
创建一个类 ,通过@ Suite 标识该类为特殊套件类,不是测试类
1. 指定类来运行
类下想要运行的用例需要被@Test注解
```java
@Suite
@SelectClasses({aaaTest.class,bbbTests.class})
public class runSuite {
}
-
指定包来运行
对于使用包名来指定的运行范围,那么该包下的所有的测试类的命名需要以Test/Tests结尾
@Suite @SelectPackages("com.autoTest0212“) public class runSuite { }
本章总结了测试方法,BUG,测试用例编写,selenium自动化测试.