自动化测试练习用的免费API网站:
https://jsonplaceholder.typicode.com
https://reqres.in
https://httpbin.org
基本概念
自动化测试时把人对软件的测试行为转化为由机器执行测试行为的一种实践
其本质是先编写一段代码,来测试另一段代码,所以实现自动化测试用例本身属于开发工作,需要投入大量的时间和精力,且已经完成的测试用例必须随着被测对象的改变而不断更新,还需要为此付出维护测试用例的成本。
因此,当使用自动化测试的维护成本高于其节省的测试成本时,自动化测试就失去了意义,需要在是否使用自动化测试上权衡取舍了。
自动化测试的优势与劣势
优势
- 可以替代大量的手工机械重复性工作,测试工程师可以把更多的时间花在更全面的用例设计和新功能的测试上
- 可以大幅提升回归测试的效率,非常适合敏捷开发过程
- 可以更好地利用无人值守时间,更频繁地执行测试,特别适合非工作时间执行测试、工作时间分析失败用例的工作模式
- 可以高效实现某些手工测试无法完成或者代价巨大的测试,比如,关键业务全天候持续运行的系统稳定性测试和高并发场景下的压力测试等
- 保证每次测试执行的操作及验证的一致性和可重复性
劣势
- 只能取代手工测试中执行频率高、机械化的重复步骤,不能完全取代手工测试
- 远比手工测试脆弱,无法应对被测系统的变化。对于执行过程中出现的明显错误和意外事件,自动化测试没有任何处理能力
- 如,某次迭代时被测目标代码中的某个关键变量var1被全局替换成var2,但是自动化测试传入的变量名仍然是var1,会导致整个自动化测试的流程无法接通。
- 自动化测试用例的开发工作量远大于单词的手工测试,所以只有当开发完成的测试用例的有效执行次数>=5时,才能收回自动化测试的成本
- 手工测试发现的缺陷数量通常比自动化测试要多,且自动化测试仅能发现回归测试的缺陷
- 自动化测试的效率很大程度上依赖于自动化测试用例的设计以及设计质量
- 实行自动化测试的初期,用例开发效率通常都很低,通常在整个自动化测试体系成熟,且测试工程师全面掌握测试工具后,大量初期开发的测试用例都需要重构
- 自动化测试开发人员必须具备一定的编程能力
使用场景
- 需求稳定、不会频繁变更的场景
- 研发和维护周期长,需要频繁执行回归测试的场景
- 软件产品比软件项目更适合执行自动化测试
- 需要在多种平台上重复运行相同测试的场景,如
- 对于GUI测试,同样的测试用例需要在不同的浏览器上执行;
- 对于移动应用测试,同样的测试用例需要在不同的移动终端上执行
- 对于一些企业软件,如果对不同的客户有不同的定制版本,各个定制版本的主体功能基本一致,仅部分功能存在微小差异,但测试也需要覆盖每个定制版本的所有功能。
- 通过手工测试无法实现或者手工测试成本太高的测试项目
- 比如需要大量用户的高并发测试
- 被测软件的开发较为规范,能够保证系统可测试性。
- 测试人员具备一定编程能力的场景
软件开发各阶段的自动化测试技术
单元测试
单元测试相关内容见单元测试 – 闲言碎语 (wfqn.xyz)
单元测试的自动化测试包含以下几个方面
- 测试用例执行的自动化
- 测试用例框架代码的自动生成
- 一些框架代码应该由自动化工具生成,如下列代码块就是基于TestNG的的单元测试代码。理想情况下,这类框架性的代码应该由自动化工具来协助生成(TestNG相关可看TestNG单元测试框架详解_testng框架-CSDN博客)
// 导入 TestNG 断言类,用于测试断言
import org.testng.Assert;
// 导入 TestNG 数据提供者注解,用于提供测试数据
import org.testng.annotations.DataProvider;
// 导入 TestNG 测试注解,用于标记测试方法
import org.testng.annotations.Test;
// 定义测试类
public class TestNGExample {
// 使用 @DataProvider 注解定义数据提供者方法
// 该方法将提供用于测试的数据
@DataProvider(name = "addMethodDataProvider")
public Object[][] dataProvider() {
// 返回一个包含多个测试案例的二维数组
// 每个内部数组包含三个元素:两个操作数和一个预期的加法结果
return new Object[][] {
{ 0, 0, 0 }, // 测试案例1:两个0相加
{ 1, 1, 2 }, // 测试案例2:两个1相加
{ -1, -1, -2 }, // 测试案例3:两个-1相加
{ 1, -1, 0 }, // 测试案例4:1和-1相加
{ Integer.MAX_VALUE, 1, Integer.MAX_VALUE + 1 } // 测试边界条件,注意可能会溢出
};
}
// 使用 @Test 注解标记测试方法,并指定使用数据提供者
@Test(dataProvider = "addMethodDataProvider")
// 定义测试方法,接受三个参数:两个整数和一个预期结果
public void testAddMethod(int a, int b, int result) {
// 创建 Calculator 类的实例,假设该类有一个 add 方法
Calculator calculator = new Calculator();
// 调用 Calculator 的 add 方法进行加法运算
int actualResult = calculator.add(a, b);
// 使用 Assert.assertEquals 断言实际结果与预期结果是否相等
// 如果不相等,测试将失败并抛出异常
Assert.assertEquals(actualResult, result, "The add method did not return the expected result.");
}
}
// 假设 Calculator 类如下定义,包含一个 add 方法
class Calculator {
// add 方法接受两个整数参数并返回它们的和
public int add(int a, int b) {
return a + b;
}
}
- 部分测试输入数据的自动生成
- 指自动化工具能够不同变量类型自动生成测试输入数据
- 假如某悲惨函数的原型是
void fun(int *p, short b)
,那么测试数据自动生成技术就会为输入参数int* p
自动生成“空”和“非空”两个指针p,然后分别执行被测函数,观察函数的执行情况。如果函数没有对空指针进行处理,那么函数fun的调用必定会抛出异常,从而发现函数的设计缺陷。同样的,对于输入参数short b也会生成超出short范围的b。
- 桩代码的自动生成
- 是指自动化工具可以对被测代码进行扫描、分析,自动为被测函数内调用的其他函数生成可编程的桩代码,并提供基于测试用例的桩代码管理机制。此时,单元测试开发这秩序重点关注桩代码内的具体逻辑实现,以及桩代码的返回值。
- 抽桩:在单元测试阶段,假如函数A内部调用的函数B是桩代码,那么在代码集成阶段,我们希望函数A不再调用假的函数B,而是调用真实的函数B,这个真实函数B代替原桩代码函数B的操作,就称为“抽桩”。
- 被测代码的自动静态分析
- 静态分析主要指代码的静态扫描,目的是识别出违反编码规则或编码风格的代码行。通常是结合项目具体的编码风格,由自动化工具通过内建规则和用户自定规则自动化完成的。目前比较常用的代码静态分析工具有Sonar和Coverity等。
- 一般来说静态分析不属于单元测试的范畴,但这部分工作一般是在单元测试阶段通过自动化工具完成的,所以也归入单元测试自动化的范畴。
- 测试覆盖率的自动统计与分析
- 单元测试用例执行结束后,自动化工具可以自动统计各种测试覆盖率,包括代码行覆盖率、分支覆盖率等。这些指标可以用来衡量单元测试用例集合的充分性和完备性
- 单元测试用例的自动执行
- 单元测试用例的自动执行是指,在每次提交代码后都会由CI/CD流水线脚本自动触发单元测试的执行。
集成代码测试
代码级集成测试是指将已经开发玩的软件模块放在一起测试
从测试用例设计和测试代码结构来看,集成代码测试和单元测试非常相似,都是对被测函数以不同的输入参数组合进行调用并验证结果。
与单元测试不同的是,集成代码测试更关注软件模块之间的接口调用和数据传递,集成代码测试中被测函数内部调用的其他函数必须是真实的,不允许使用桩代码代替。
集成代码测试对测试框架的要求非常高,除了可以顺利装载软件模块外,测试框架还必须装在其他相互依赖的模块,使被测软件模块可运行。
集成代码测试主要应用在早期非护粮网的传统软件企业,即软件包含大量功能的项目中。现在的开发理念追求的是系统复杂性的解耦,避免“大单体”应用,采用web service或者RPC调用的方式来协作实现各个功能,所以现在的互联网企业一般不做集成代码测试。
Web Service测试
Web Service测试,主要指SOAP API和REST API两类API测试,最典型的是采用SoapUI或Postman等类似的工具进行API测试。于是API自动化测试框架出现了。
如果采用API自动化测试框架来开发测试用例,那么这些测试用例的表现形式就是代码。如下为一个创建用户API的例子和基于代码的API测试用例
// 这是一个测试方法,用于测试创建用户的功能。
public void testCreateUser() {
// 提供必要的参数
String userId = "exampleUserId";
String password = "examplePassword";
// 创建API实例并构建请求
CreateUserAPI createUserAPI = new CreateUserAPI();
Request req = createUserAPI.buildRequest(userId, password);
// 发送请求并获取响应
Response response = req.request();
// 断言响应的状态码是否为200
assert(response.statusCode == 200);
}
public class CreateUserAPI extends RestAPI {
public static String ENDPOINT = "https://xxx.com/user/create/v2/{userId}/";
public CreateUserAPI() {
// 调用父类构造方法,指定请求方法为PUT,并传入API的端点
super(Method.PUT, ENDPOINT);
}
// 构建请求方法,接收userId和password参数
public Request buildRequest(String userId, String password) {
// 构建基础请求
Request req = _buildRequest();
// 添加URL路径参数
req.getEndpoint().addInlineParam("userId", userId);
// 添加请求体参数(假设需要传递旧密码)
req.getEndpoint().addParam("password", password);
// 返回构建好的请求
return req;
}
}
开发基于代码的API测试用例的步骤
- 准备API调用时需要的测试数据
- 准备API的调用参数并发起API调用
- 验证API调用的返回结果
目前流行的API自动测试框架是REST Assured,其用法可以参考官方网站http://rest-assured.io和Rest-Assure框架最全使用教程_restassured-CSDN博客
Web Service测试自动化除了API测试用例自动化外,还包括以下方面
- 测试脚手架的自动生成
- 测试脚手架生成自动生成的脚手架代码,通常包含了被测API的调用、测试数据与脚本的分离,以及响应验证的空实现。让测试人员的精力不被浪费在代码层面等非测试业务
- 部分测试输入数据的自动生成
- API测试针对API的参数以及API调用的有效负载自动生成部分测试输入数据,数据生成原则同样遵循边界值原则
- 响应验证的自动化
- 对于API调用返回结果的验证,通常关注的点是返回的状态码(status code)、Scheme结构以及具体的参数值。
- 核心思想是自动比较两次相同的API调用的返回结果,并自动识别出有差异的字段值。
- 基于SopaUI或Postman的脚本自动生成
- 使用工具进行Web Service测试中,在引入了基于代码实现的API测试框架后,需要重新将测试用例用代码重写一遍。
- Postman和笔者工作使用的Apifox都支持将工具内的测试用例转换成代码。
- 对于不支持自动转换的,就需要开发自动化的代码转换工具,输入是工具的测试用例元数据(即测试用例的JSON元文件),输出是符合API测试框架规范的基于代码实现的测试用例
GUI自动化测试
传统Web浏览器的GUI自动化测试:主流的开源方法采用Selenium
移动端原生应用的GUI自动化测试,通常采用主流的Appium