目录
一、HTTP协议
URL
URL:是互联网上标准资源的地址,一般称为统一资源定位符
组成:协议://hostname[:post]/path/[?查询参数1 & 查询参数2]
默认端口号:http(80),https(443)
URL由哪几部分组成?
- 协议
- 服务器地址
- 端口号
- 资源路径
- 参数
HTTP协议
HTTP:超文本传输协议,基于请求与响应的应用层协议
作用:规定了客户端与服务器之间信息传递规范,是二者共同遵守的协议
组成:
- HTTP请求:定义请求数据格式 [ 请求行、请求头、请求体 ]
- HTTP响应:定义响应数据格式 [ 状态行、响应头、响应体 ]
请求行
位置:请求数据第一行
作用:说明请求方法、访问的资源、协议版本
常用请求方法:
- GET:从服务器获取资源
- POST:在服务器新建一个资源
- PUT:在服务器更新资源
- DELETE:从服务器删除资源
请求行
位置:请求数据第二行到空白行之间
作用:通知服务器客户端请求信息
特点:请求头部由键值对组成,每行一对
Content-Type:请求体数据类型
- text/html:HTML格式
- image/jpeg:jpg图片格式
- application/json:JSON数据格式
- application/x-www-form-urlencodeed:表单默认的提交数据格式
- multipart/form-data:在表单中进行文件上传时使用
请求体
位置:空白行之后的内容
作用:传输数据实体
注意:请求体常在POST、PUT方法中使用
常配合的请求头:Content-Type 和 Content-Length
状态行
位置:响应数据第一行
作用:描述服务器处理结果
内容:状态行由协议版本号、状态码、状态消息组成
状态码:三位数字组成。第一个数字定义响应类别
- 1XX:指示信息
- 2XX:成功
- 3XX:重定向
- 4XX:客户端错误
- 5XX:服务器错误
响应头
位置:第二行到空白行之间
作用:描述客户端要使用的一些附加信息
特点:响应头由键值对组成,每行一对
响应体
位置:响应数据空白行之后
作用:服务器返回的数据实体
特点:有图片、json、xml、html等多种类型
二、接口规范
作用:让前端开发与后台接口开发人员更好的配合,提高工作效率
常见接口规范:
- 传统接口风格
- RESTful接口风格
传统接口风格
示例:对用户进行相关操作的相关接口,包括增删改查
RESTful
RESTful:一种网络应用程序的设计风格和开发方式,提供了一组设计原则和约束条件
示例:
特点:
- 请求API和URL用来定位资源
- 通过标准HTTP方法对资源进行增删改查操作
- 利用HTTP状态码返回状态信息
区别
三、Postman接口测试
1.拿到一个接口项目之后,先测试业务接口还是先测试单个接口?
- 先测试业务接口
2.如何测试业务接口?
- 根据业务流程图梳理业务路径
- 设计测试用例覆盖每一条业务路径
3.如何进行接口文档解析?
- 分析接口之间的依赖关系
- 分析接口请求(如:URL、请求方法、请求头、请求参数类型、请求参数)
- 分析接口响应(如:响应状态码、响应数据等)
接口测试用例
Postman
介绍:Postman一款接口调试工具
特点:支持Mac、Windows和Linux
如何使用Postman发送请求并查看响应结果?
- 设置请求方法
- 设置URL
- 设置请求头
- 设置请求数据
- 点击Send发送请求
- 查看响应状态码
- 查看相应体数据
自动关联
1.Postman自动关联解决了什么技术问题?
- 接口之间需要自动传递数据
2.Postmen自动关联实现思路:
- 提取关联数据:pm.response.json()
- 保存关联数据:pm.environment.set()
- 引用关联数据:{{变量名}}
3.如何针对单个接口设计测试用例?
- 正向:必填参数、全部参数
- 逆向:空、类型错误、长度错误、规则不符
断言
作用:让Postman工具代替人工自动判定预期结果和实际结果是否一致
用法:点击Tests--->选择断言方式--->在Test Results查看断言结果
响应状态码断言
模板名称:Status code:Code is 200
模板内容:(只需修改200)
// 判断响应状态码是否等于200 pm.test("Status code is 200",function(){ pm.response.to.have.status(200); }); pm.test() // 参数1:字符串-测试断言名称 // 参数2:回调函数-具体断言语句 // 判断是否包含指定的状态码 pm.response.to.have.status(code:Number)
包含指定字符串断言
模板名称:Response body:Contains string
模板内容:(只需修改"string_you_want_to_search"字符串)
// 判断响应结果是否包含指定字符串 pm.test("Body matches string",function(){ pm.expect(pm.response.text()).to.include("string_you_want_to_search"); }); // 通过一系列调用链判断是否符合预期 pm.expect() // 接收实际结果 .to // 连接符,用于连接断言方式和预期结果 .include() // 获取响应结果的文本格式数据 // 获取响应结果的文本格式数据 pm.presponse.text();
JSON数据断言
模板名称:Response body:JSON value check
模板内容:(修改jsonData.value 和 100)
// 校验响应的JSON数据 pm.test("Your test name",function(){ var jsonData = pm.response.json(); pm.expect(jsonData.value).to.eql(100); }); // 通过一系列调用链判断是否符合预期 pm.response.json() // 获取响应结果的json数据 .eql() // 用于指定断言方式和预期结果
参数化
场景:测试脚本中仅测试数据不一样,使用参数化提高脚本复用
步骤:
- 测试书保存在数据文件单独维护
- 引用数据文件实现脚本循环调用
实现:
准备数据文件:
{"username":"root","password":"123456","status":"200","message":"成功","msg":"操作成功"}
引用数据文件:
1.请求参数中获取
{{}}引用相关对象的key
eg:{{username}}
2.代码中获取
postman内置data对象引用key
eg.data.status
选择数据文件:运行测试集时选择数据文件
四、接口自动化基础
接口自动化测试
接口自动化:使用工具或代码代替人对接口进行测试的技术
测试目的:防止开发修改代码时引入新的问题
测试时机:
开发进行系统测试转测前,可以先进行接口自动化脚本的编写
开发进行系统测试转测后,有限进行系统测试用例的执行,在进行接口自动化脚本的编写
接口自动化测试流程
- 选取自动化测试用例
- 搭建自动化测试环境
- 搭建自动化测试框架
- 代码实现自动化
- 输出测试报告
- 实现持续集成
核心技术:
- 编程语言:python
- 测试框架:pytest
- 接口请求:requests
接口自动化框架设计思路
- 搭建基础框架:定义项目目录结构
- 通用功能类封装:封装通用功能如:数据库工具类等
- 接口对象封装与调用:封装接口API对象+PyTest框架编写测试脚本
- 测试数据参数化:测试数据json文件设计、参数化实现
- 用例组织运行:组织测试用例运行,生成测试报告
搭建基础框架-定义项目目录结构
apiTestFramework # 项目名称
|——api # 定义封装被测系统的接口
|——script # 定义测试用例脚本
|——data # 存放测试数据文件
|——report # 存放生成的测试报告
|——common #存放通用工具类
|——config.py #定义项目的配置信息
|——pytest.ini #pytest配置文件
五、Requests库
Requests介绍
Requests库:python中的“浏览器”,基于urllib的HTTP库
安装:pip3 install requests
验证:pip3 show requests
操作步骤:
- 导包
- 发送接口请求
- 查看响应数据
Requests发送请求
requests.请求方法(url, params=None, data=None, json=None, headers=None)
说明:
- 常见的请求方法:get/post/put/delete
- url: 请求的url地址
- params: 请求查询参数
- data: 请求体为form表单参数
- json: 请求体为json参数
- headers: 请求头参数
Response查看响应
示例:
# 导包 import requests # 发送请求 response = requests.get(url="http://www.baidu.com") # 查看响应 print(response.status_code) print(response.text)
对象接口封装
核心思想:代码分层思想
接口对象层:
- 根据接口API文档封装
- 重点关注如何调用接口
- 请求参数从测试脚本层传递
- 接口响应结果返回给脚本层
测试脚本层:
- 重点关注测试数据准备和断言
- 重点关注业务流程的处理
- 直接调用接口对象层发送请求
Requests处理multipart/form-data
requests.请求方法(url, data=None, json=None, headers=None, files=None)
说明:
files:上传的文件
符合提交multipart/form-data数据?
1.读取文件数据
f = open("test.pdf", "rb")
2.设置请求数据
response = requests.post(url=xxx, files={"file":f})
六、登录示例
api文件夹内容
login.py
# 导包 import requests # 创建接口类 class LoginAPI: # 初始化 def __init__(self): self.url_verify = "http://kdtx-test.itheima.net/api/captchaImage" self.url_login = "http://kdtx-test.itheima.net/api/login" # 验证码 def get_verify_code(self): return requests.get(url=self.url_verify) # 登录 def login(self, test_data): return requests.get(url=self.url_login, json=test_data)
script文件夹内容
test01_login.py
# 导包 form api.login import LoginAPI # 创建测试类 class TestLoginAPI: # 初始化 uuid = None # 前置处理 def setup(self): # 实例化接口类 self.login_api = LoginAPI() # 获取验证码 response = self.login_api.get_verify_code() print(response.json()) # 提取验证码接口返回的uuid参数值 TestLoginAPI.uuid = response.json().get("uuid") print(TestLoginAPI.uuid) # 后置处理 def teardown(self): pass # 登录成功 def test01_success(self): login_data = { "username":"manager", "password":"123456", "code":"2", "uuid":TestLoginAPI.uuid } response = self.login_api.login(test_data=login_data) # 断言响应状态码为200 assert 200 == response.status_code # 断言响应数据包含“成功” assert '成功' in response.text # 断言响应json数据中code值 assert 200 == response.json().get("code") # 登录失败(用户名为空) def test02_witout_username(self): login_data = { "username":"", "password":"123456", "code":"2", "uuid":TestLoginAPI.uuid } response = self.login_api.login(test_data=login_data) # 断言响应状态码为200 assert 200 == response.status_code # 断言响应数据包含“错误” assert '错误' in response.text # 断言响应json数据中code值 assert 500 == response.json().get("code") # 登录失败(未注册用户) def test03_username_not_exist(self): login_data = { "username":"jack666", "password":"123456", "code":"2", "uuid":TestLoginAPI.uuid } response = self.login_api.login(test_data=login_data) # 断言响应状态码为200 assert 200 == response.status_code # 断言响应数据包含“错误” assert '错误' in response.text # 断言响应json数据中code值 assert 500 == response.json().get("code")
Python常见断言方式有哪些?
- 相等断言(assert test_data == 'xxx')
- 包含断言(assert 'xxx' in test_data)
数据驱动
数据驱动:以测试数据驱动脚本执行,维护焦点从脚本转向测试数据的一种自动化测试设计模式
好处:将测试数据和测试脚本进行分离,便于测试数据的处理
pytest中parametrize装饰器
作用:遍历所有测试数据并运行测试方法
语法:
@pytest.mark.parametrize(②保存数据参数名, ①测试数据)
def test_method(self, ③参数名)
pass
示例:
test_data=[("manager","123456"),("","123456"),("jack666","123456")] @pytest.mark.parametrize("mobile,passwd",test_data) def test_login(self, mobile,passwd) pass
# 导包 form api.login import LoginAPI import pytest # 测试数据 test_data = [ ("manager","123456",200,'成功',200), ("","123456",200,'错误',500), ("jack666","123456",200,'错误',500) ] # 创建测试类 class TestLoginAPI: # 初始化 uuid = None # 前置处理 def setup(self): # 实例化接口类 self.login_api = LoginAPI() # 获取验证码 response = self.login_api.get_verify_code() print(response.json()) # 提取验证码接口返回的uuid参数值 TestLoginAPI.uuid = response.json().get("uuid") print(TestLoginAPI.uuid) # 后置处理 def teardown(self): pass # 登录成功 @pytest.mark.parametrize("username, password, status, message, code",test_data) def test01_success(self, username, password, status, message, code): login_data = { "username":username, "password":password, "code":"2", "uuid":TestLoginAPI.uuid } response = self.login_api.login(test_data=login_data) # 断言响应状态码为200 assert status == response.status_code # 断言响应数据包含“成功” assert message in response.text # 断言响应json数据中code值 assert code == response.json().get("code")
将测试数据和测试脚本分开,需要将测试数据转为json格式,存放到data文件夹下login.json
[ { "username":"manager", "password":"123456", "status":200, "message":"成功", "code":200 }, { "username":"", "password":"123456", "status":200, "message":"错误", "code":500 }, { "username":"jack666", "password":"123456", "status":200, "message":"错误", "code":500 }, ]
测试脚本读取json文件
# 导包 form api.login import LoginAPI import pytest import json # 测试数据 # test_data = [ # ("manager","123456",200,'成功',200), # ("","123456",200,'错误',500), # ("jack666","123456",200,'错误',500) # ] # 读取json文件 def build_data(json_file): # 定义空列表 test_data = [] # 打开json文件 with open(json_file, "r") as f: # 加载json文件数据 json_data = json.load(f) # 循环遍历测试数据 for case_data in json_data: # 转换数据格式[{},{}] ==> [(),()] username = case_data.get("username") password = case_data.get("password") status = case_data.get("status") message = case_data.get("message") code = case_data.get("code") test_data.append(username, password, status, message, code) # 返回处理之后测试数据 return test_data # 创建测试类 class TestLoginAPI: # 初始化 uuid = None # 前置处理 def setup(self): # 实例化接口类 self.login_api = LoginAPI() # 获取验证码 response = self.login_api.get_verify_code() print(response.json()) # 提取验证码接口返回的uuid参数值 TestLoginAPI.uuid = response.json().get("uuid") print(TestLoginAPI.uuid) # 后置处理 def teardown(self): pass # 登录成功 @pytest.mark.parametrize("username, password, status, message, code",build_data(json_file="../data/login.json")) def test01_success(self, username, password, status, message, code): login_data = { "username":username, "password":password, "code":"2", "uuid":TestLoginAPI.uuid } response = self.login_api.login(test_data=login_data) # 断言响应状态码为200 assert status == response.status_code # 断言响应数据包含“成功” assert message in response.text # 断言响应json数据中code值 assert code == response.json().get("code")
项目配置文件
由于在每个测试接口中都定义了项目环境域名url地址,导致后续将测试地址改为正式地址较为麻烦,所以将域名配置到config.py文件下
我们使用相对路径时,运行会造成路径错误,将项目路径配置到文件中
config.py
# 导包 import os # 设置项目环境域名 BASE_URL = "http://kdtx-test.itheima.net" # 获取项目根路径 BASE_PATH = os.path.dirname(__file__)
/api/login.py
# 导包 import requests import config # 创建接口类 class LoginAPI: # 初始化 def __init__(self): # 指定url基本信息 # self.url_verify = "http://kdtx-test.itheima.net/api/captchaImage" self.url_verify = config.BASE_URL + "/api/captchaImage" # self.url_login = "http://kdtx-test.itheima.net/api/login" self.url_login = config.BASE_URL + "/api/login" # 验证码 def get_verify_code(self): return requests.get(url=self.url_verify) # 登录 def login(self, test_data): return requests.get(url=self.url_login, json=test_data)
# 上传合同成功 def test01_upload_contract(self): #读取pdf文件 # f = open("../data/test.pdf","rb") f = open(config.BASE_PATH + "/data/test.pdf","rb") response = self.contract_api_upload_contract(test_data=f, token=TestContractBusiness.token)
七、Allure报告
allure介绍
介绍:
- 能生成美观易读的报告
- 支持多种开发语言,如java、python等
- 能快速上手
操作步骤:
- 生成测试结果文件(json文件)
- 使用allure命令生成在线报告
操作步骤
1.生成测试结果文件
安装:pip insatll allure-pytest
使用步骤:
1.将pytest配置文件中的命令行参数加上如下代码
--alluredir report
2.编写好测试脚本后,在命令行行中运行pytest
[pytest] # 指定运行模式,allure产生目录 addopts = -s --alluredir report # 指定运行的代码文件所在目录 testpath = ./sscripts # 目录下面哪些文件会被运行 python_files = test*.py # 文件下哪些类会被运行 python_classes = Test* # 类下面的哪些方法会被运行 python_functions = test*
pytest.ini文件
[pytest] addopts = -s --alluredir report testpath = ./sscripts python_files = test*.py python_classes = Test* python_functions = test*
3.程序运行结束收,会在项目的report目录中生成一些json文件
2.使用allure生成在线报告
安装:
- 下载https://github.com/allure-framework/allure2/releases
- 解压压缩包到一个不包含中文路径的目录
- 右键我的电脑- 属性 - 高级设置 - 环境变量 - 找到系统环境变量的path项 - 增加alure到bin目录
- 在命令行中输入 allure --version 命令,能显示allure版本信息,即为成功
在终端运行pytest,产生测试结果文件(json文件)
产生报告:allure serve report