接口自动化测试小结

一、接口测试的概念

1、接口:指系统或组件之间的交互点,通过这些交互点可以实现数据之间的交互。(数据交互的通道)

2、接口测试:对系统或组件之间的接口进行测试,主要用于检测外部系统与系统之间以及系统内部之间的数据交换、传递和控制管理过程,以及系统间的相互逻辑依赖关系。

3、接口自动化测试:使用程序或者工具自动的完成对进口进行测试。

二、接口测试的实现方式

  • 工具:Postman、Jmeter
  • 代码:python + requests

三、接口测试的流程

  • 需求分析
    • 主要依据是需求文档
  • 挑选需要做接口测试的功能
  • 接口文档解析
  • 设计测试用例
  • 执行测试
    • 使用接口测试工具实现
    • 通过编写代码实现
  • 接口缺陷管理与跟踪
  • 接口自动化持续集成

四、接口自动化测试的流程

  • 将功能用例抽取转化成自动化用例
  • 搭建测试环境 (工具环境或者代码环境)
  • 使用代码搭建自动化结构目录
  • 编写用例脚本
  • 执行用例脚本
  • 查看测试报告
  • 持续集成

五、接口测试用例

ID系统模块用例名称接口名称请求URL请求类型请求头请求参数类型请求参数预期结果测试结果
001前台系统登录登录成功登录
http://ttapi.research.itcast.cn
/mp/v1_0/authorizations
POST 
{"Content-Type": "application/json"}
json
{"mobile":mobile,"code":code}
002文章发布文章发布文章 
http://ttapi.research.itcast.cn
/mp/v1_0/articles
POST 
{"Content-Type": "application/json",
"Authorization": "Bearer token"}
json 
{"title":title,"content":content,"channel_id":channel_id,"cover":{"type":0,"images":[]}}
003后台管理系统登录登录成功登录
http://ttapi.research.itcast.cn
/mis/v1_0/authorizations
POST 
{"Content-Type": "application/json"}
json 
data = {"account":account,"password":password}
004文章查询文章查询文章 
http://ttapi.research.itcast.cn
/mis/v1_0/articles
GET 
{"Content-Type": "application/json",
"Authorization": "Bearer token"}
QueryString 
{"title":api.title,"channel":api.channel}
005审核文章审核文章 
http://ttapi.research.itcast.cn
/mis/v1_0/articles
PUT 
{"Content-Type": "application/json",
"Authorization": "Bearer token"}
json 
{"article_ids":[api.article_id],"status":2}

六、项目搭建

(1) 初始化项目

  • 目录名称

(2)创建目录结构

  • 目录结构包括:api、scripts、data、log、report、tool

 【关于项目目录结构的说明】

  • api:资源对象接口封装(相当于web自动化测试中的page)
  • scripts:资源接口测试脚本
  • data:数据驱动
  • log:日志
  • report:测试报告
  • tool:工具类

(3)公共变量的抽取

通过分析接口测试用例,我们可以提取如下公共变量,分别为:

  • host域名及端口:http://ttapi.research.itcast.cn
  • 请求消息头headers:{"Content-Type": "application/json"}

为了方便api包下的模块调用提取的公共变量,我们可以将公共变量存放在api包下的__init__.py模块中:

 【以下为本接口自动化测试项目抽取的所有公共变量】

 1 """公共变量"""
 2 from tool.read_yaml import read_yaml
 3 
 4 # 1. 请求域名
 5 host = "http://ttapi.research.itcast.cn"
 6 
 7 # 2. 请求信息头
 8 headers = {"Content-Type": "application/json"}
 9 
10 # 3. 用于接收服务器返回的文章id,用于文章审核是调用
11 article_id = None
12 
13 # 接收发布文章读取的数据
14 data_article = read_yaml("mt_article.yaml")
15 print(data_article)
16 
17 # 文章title
18 title = data_article[0][0]
19 # 文章内容
20 content = data_article[0][1]
21 # 文章所属频道id
22 channel_id = data_article[0][2]
23 # 文章所属频道
24 channel = data_article[0][3]

(4)资源Api结构搭建及实现

【前端媒体资源】

1、前端媒体资源api结构搭建 -- 主要包括初始化以及待测试的各个接口 -- api_mt.py

  • 初始化
    • 定义登录接口url
    • 定义发布文章接口url
  • 登录接口封装
    • 定义请求数据
    • 发送post请求返回响应对象
  • 发布文章接口封装
    • 定义请求数据
    • 发送post请求返回响应对象

2、前端媒体资源api结构的实现

 【代码具体实现如下】

 1 import api
 2 import requests
 3 from tool.get_log import GetLog
 4 
 5 log = GetLog.get_logger()
 6 
 7 class ApiMt:
 8 
 9     # 1. 初始化
10     def __init__(self):
11         # 1. 登录接口url
12         self.url_login = api.host + "/mp/v1_0/authorizations"
13         log.info("正在初始化自媒体登录url:{}".format(self.url_login))
14         # 2. 发布文章接口url
15         self.url_article = api.host + "/mp/v1_0/articles"
16         log.info("正在初始化自媒体发布文章url:{}".format(self.url_article))
17         pass
18 
19     # 2. 登录接口
20     def api_mt_login(self,mobile,code):
21         """
22 
23         :param mobile: 手机号
24         :param code: 验证码
25         :return: 响应对象
26         """
27         # 1. 定义请求数据
28         data = {"mobile":mobile,"code":code}
29         # 2. 调用post方法
30         log.info("正在调用自媒体登录接口,请求数据:{}".format(data))
31         return requests.post(url=self.url_login, json=data, headers=api.headers)
32 
33     # 3. 发布文章接口
34     def api_mt_article(self,title,content,channel_id):
35         """
36 
37         :param title: 文章标题
38         :param content: 文章内容
39         :param channel_id: 频道id
40         :param cover: 封面 0: 为自动
41         :return: 响应对象
42         """
43         # 1. 定义请求数据
44         data = {"title":title,"content":content,"channel_id":channel_id,"cover":{"type":0,"images":[]}}
45         # 2,调用post方法
46         log.info("正在调用自媒体发布文章接口,请求数据:{}".format(data))
47         return requests.post(url=self.url_article, json=data, headers=api.headers)  

【注意】

在发送请求出传递请求头参数时,注意headres的拼写

【后台管理资源】

1、后台管理资源api结构的搭建 -- 主要包括初始化以及待测试的各个接口 -- api_ht.py

  • 初始化
    • 定义登录url
    • 定义查询文章url
    • 定义审核文章url
  • 登录
    • 定义请求数据
    • 发送post请求返回响应对象
  • 查询文章
    • 定义请求数据
    • 发送get请求返回响应对象
  • 审核文章
    • 定义请求数据
    • 发送put请求返回响应对象

2、后台管理资源api结构的实现

【代码具体实现如下】


 1 import api
 2 import requests
 3 from tool.get_log import GetLog
 4 
 5 log = GetLog.get_logger()
 6 
 7 class ApiHt:
 8 
 9     # 初始化: 用于获取各个接口的url
10     def __init__(self):
11         # 1. 登录url
12         self.url_login = api.host + "/mis/v1_0/authorizations"
13         log.info("正在初始化后台管理系统 登录url:{}".format(self.url_login))
14         # 2. 查询url
15         self.url_search = api.host + "/mis/v1_0/articles"
16         log.info("正在初始化后台管理系统 查询url:{}".format(self.url_search))
17         # 3. 审核url
18         self.url_audit = api.host + "/mis/v1_0/articles"
19         log.info("正在输出化后台管理系统 审核url:{}".format(self.url_audit))
20 
21 
22     # 登录接口
23     def api_ht_login(self,account,password):
24         """
25 
26         :param account: 账号
27         :param password: 密码
28         :return: 响应信息
29         """
30         # 1. 参数数据
31         data = {"account":account,"password":password}
32         log.info("正在调用后台管理系统登录接口,请求的数据为:{} 请求的信息头为:{}".format(data,api.headers))
33         # 2. 调用post方法
34         return requests.post(url=self.url_login,json=data,headers=api.headers)
35 
36     # 查询文章接口
37     def api_ht_search(self):
38         """
39         :param title: 文章标题 数据来源于api.__init__.py模块
40         :param channel: 文章频道 数据来源于api.__init__.py模块
41         :return:
42         """
43         # 1. 参数数据
44         data = {"title":api.title,"channel":api.channel}
45         log.info("正在调用后台管理系统查询文章接口,请求的数据为:{} 请求的信息头为:{}".format(data,api.headers))
46         # 2. 调用get方法
47         return requests.get(url=self.url_search,params=data,headers=api.headers)
48 
49     # 审核文章接口
50     def api_ht_audit(self):
51         """
52         :param article_ids: 文章id,数据来源发布文章后服务器生成的
53         :param status: 2 为文章审核通过
54         :return: 响应对象
55         """
56         # 1. 参数数据
57         data = {"article_ids":[api.article_id],"status":2}  # 2 为文章审核通过
58         log.info("正在调用后台管理系统文章审核接口,请求的数据为:{} 请求的信息头为:{}".format(data,api.headers))
59         # 2. 调用put方法
60         return requests.put(url=self.url_audit,json=data,headers=api.headers)

【说明】

  • 在实现搭建的api结构时,查询文章和审核文章的参数数据都是直接从api包下的__init__.py模块中直接读取的,因为参数数据已通过read_yaml工具读取并存储在__init__.py模块中;
  • 在发送请求时,注意headers单词的拼写。

(5)测试业务层结构搭建及实现

【前端媒体资源测试业务】

1、前端媒体测试业务层搭建

  • 初始化
    • 获取ApiMt对象
  • 登录接口测试方法
    • 调用登录接口
    • 提取响应数据中的token信息
    • 断言(参数化)
  • 发布文章接口测试方法
    • 调用发布文章接口
    • 获取响应中的数据中文章id
    • 断言(参数化)

2、公共方法的提取

由于在断言时,前后台接口所涉及的5条测试用例,据需要进行断言操作,且断言操作的内容基本上都是比较响应状态码以及返回数据中的message;

同时在前后台登录接口中均涉及token数据的提取,因此我们可以将断言和token数据的提取封装成成相应的工具方法,在测试脚本中需要时直接调用工具类中的方法即可。

代码实现如下:

1 """
 2 用于提取测试脚本中的公共方法:
 3     - 获取token
 4     - 断言
 5 """
 6 import api
 7 from tool.get_log import GetLog
 8 
 9 log = GetLog.get_logger()
10 
11 class Tool:
12 
13     @classmethod
14     def common_token(cls,resp):
15         # 获取token
16         token = resp.json()["data"]['token']
17         # 将token添加到headers中
18         api.headers["Authorization"] = "Bearer " + token
19         log.info("正在提取token,提取后的headers为:{}".format(api.headers))
20         print("添加token后的headers为:", api.headers)
21 
22     @classmethod
23     def common_assert(cls,resp,status_code=201):
24         log.info("正在调用公共断言方法!")
25         # 断言响应状态码
26         assert status_code == resp.status_code
27         # 断言响应内容
28         assert "OK" == resp.json()["message"]

-- 断言操作中默认的响应状态为201,在在实际的测试过程中,如果存在其他的响应状态码,可以在调用该断言方法时进行修改

3、登录、发布文章测试用例实现

 1 from api.api_mt import ApiMt
 2 from tool.tool import Tool
 3 from tool.get_log import GetLog
 4 from tool.read_yaml import read_yaml
 5 import pytest
 6 import api
 7 
 8 log = GetLog.get_logger()
 9 
10 import api
11 class TestMt:
12 
13     # 1. 初始化
14     def setup_class(self):
15         # 获取ApiMt对象
16         self.mt = ApiMt()
17         pass
18 
19     # 2. 登录接口测试方法
20     @pytest.mark.parametrize("mobile,code",read_yaml("mt_login.yaml"))
21     def test_01_mt_login(self,mobile,code):
22         # 调用登录接口
23         resp = self.mt.api_mt_login(mobile=mobile,code=code)
24         # 打印数据结果
25         print("登录结果为:", type(resp.json()))
26         try:
27             # 提取token
28             Tool.common_token(resp)
29             # 断言
30             Tool.common_assert(resp)
31         except Exception as e:
32             # 写日志
33             log.error("断言错误:{}".format(e))
34             # 抛异常
35             raise
36 
37         # 以下方法封装成tool
38         # # 提取token
39         # token = resp.json()["data"]['token']
40         # # 将token追加到请求头 -- 保存到api包的__init__.py中
41         # api.headers["Authorization"] = "Bearer " + token
42         # print("添加token后的headers为:", api.headers)
43         # # 断言状态码
44         # assert 201 == resp.status_code
45         # # 断言响应信息
46         # assert "OK" == resp.json()["message"]
47 
48     # 3. 发布文章接口测试方法
49     def test_02_mt_article(self,title=api.title,content=api.content,channel_id=api.channel_id):
50         # 1. 调用发布文章接口
51         resp = self.mt.api_mt_article(title,content,channel_id)
52         # 2. 获取id
53         api.article_id = resp.json()["data"]['id']   
54         print("发布文章成功后的id:{}".format(api.article_id))
55         try:
56             # 3. 断言
57             Tool.common_assert(resp)
58         except Exception as e:
59             # 1. 日志
60             log.error("断言失败:{}".format(e))
61             # 2. 异常抛出
62             raise

【说明】

  • 在实现发布文章接口测试方法时,我们需要提取响应数据中文章id的信息,并将其赋值给api包下的__init__.py模块中的article_id变量,因为后台管理系统在查询文章使需要使用到该article_id的值;
  • 在给测试脚本命名时,除了以test开头外,名称中最好不要出现数字。
【后台管理资源测试业务】

1、后台管理测试业务层搭建

  • 初始化
    • 获取ApiHt对象
  • 登录测试方法
    • 调用登录接口
    • 提取响应信息中的token值
    • 断言
  • 查询文章测试方法
    • 调用查询文章接口
    • 断言
  • 审核文章测试方法
    • 调用审核文章接口
    • 断言

2、登录、查询文章以及审核文章测试用例实现

 【测试用例代码实现】


 1 from api.api_ht import ApiHt
 2 from tool.tool import Tool
 3 from tool.get_log import GetLog
 4 from tool.read_yaml import read_yaml
 5 import api
 6 import pytest
 7 
 8 log = GetLog.get_logger()    # 用于记录日志信息
 9 
10 class TestHt:
11 
12     # 1. 初始化
13     def setup_class(self):
14         # 获取ApiHt对象
15         self.ht = ApiHt()
16         pass
17 
18     # 2. 登录
19     @pytest.mark.parametrize("account,password",read_yaml("ht_login.yaml"))
20     def test_01_ht_login(self,account,password):
21         # 调用登录接口
22         resp = self.ht.api_ht_login(account=account,password=password)
23         # 提取token
24         Tool.common_token(resp)
25         print("后台管理系统登录后,请求的headers为:{}".format(api.headers))
26         try:
27             # 断言
28             Tool.common_assert(resp)
29         except Exception as e:
30             # 1. 日志
31             log.error("断言错误:{}".format(e))
32             # 2. 抛异常
33             raise
34 
35     # 3. 查询文章
36     # -- 说明:由于后台无法查看的审核文章的信息,因此在断言时出错,因此导致查询文章和审核文章的用例无法继续向下运行
37     def test_02_ht_search(self):
38         # 1. 调用查询文章接口
39         resp = self.ht.api_ht_search()
40         print("查询文章的信息为:",resp.json())
41         try:
42             # 2. 断言
43             Tool.common_assert(resp,status_code=200)    # 注意:状态码为200并且为int类型
44         except Exception as e:
45             # 日志记录
46             log.error("断言出错:{}".format(e))
47             # 抛异常
48             raise
49 
50     # 4. 审核文章
51     def test_03_ht_audit(self):
52         # 1. 调用审核文章接口
53         resp = self.ht.api_ht_audit()
54         try:
55             # 2. 断言
56             Tool.common_assert(resp)
57         except Exception as e:
58             # 日志记录
59             log.error("断言错误:{}".format(e))
60             # 抛异常
61             raise

【补充说明】

在实现业务的测试用例时,我们还使用到了参数化以及日志记录。

与Web自动化测试,我们仍然使用data包下的.yaml文件来存储测试数据,使用tool包下的read_yaml.py模块来读取测试数据(直接复制web自动化测试项目中的read_yaml.py模块)。同时为了便于分析测试结果,我们还可以在api、scripts包下的模块中添加相应的日志记录,具体实现如下:

  • 前端登录测试数据

  • 前端发布文章测试数据

  • 后台管理登录测试数据

  •  测试数据读取

1 # 用于读取yaml中的数据信息
 2 
 3 import os
 4 from config import BASE_PATH
 5 import yaml
 6 
 7 # 用于读取yaml中的数据
 8 def read_yaml(filename):
 9     file_path = BASE_PATH + os.sep + 'data' + os.sep + filename   # os.sep表示文件的路径分隔符,在windows系统中表示'\',在linux系统中表示'/'
10     # 定义空列表,组装测试数据
11     arr = []
12     # 获取文件流
13     with open(file_path,'r',encoding="utf-8") as f:     # 读取文件注意指定编码方式
14         # 遍历 调用yaml.safe_load(f).values()
15         for datas in yaml.safe_load(f).values():
16             #print("hello")   # 此时循环只遍历一次
17             arr.append(tuple(datas.values()))
18         # 返回结果
19         return arr
20 
21 if __name__ == '__main__':
22     print(read_yaml("mt_login.yaml"))

  • 日志记录

 1 import logging
 2 import logging.handlers
 3 import os
 4 from config import BASE_PATH
 5 
 6 """
 7 确保生成的日志为同一个对象
 8 """
 9 class GetLog:
10 
11     # 定义类属性,保存日志
12     __logger = None
13 
14     @classmethod
15     def get_logger(cls):
16         # 判断日志是否为空
17         if cls.__logger is None:
18             # 为空,则创建日志器
19             cls.__logger = logging.getLogger('myLog_mt')
20             # 修改默认级别 -- INFO
21             cls.__logger.setLevel(logging.INFO)
22             # 创建处理器 -- 将日志信息输出到指定的文件中
23             log_path = BASE_PATH + os.sep + "log" + os.sep + "mt.log"
24             th = logging.handlers.TimedRotatingFileHandler(filename=log_path,
25                                                            when="midnight",
26                                                            interval=1,
27                                                            backupCount=3,
28                                                            encoding="utf-8")
29             # 创建格式器
30             fmt = "%(asctime)s %(levelname)s [%(filename)s(%(funcName)s:%(lineno)d)] - %(message)s"
31             fm = logging.Formatter(fmt)
32             # 将格式器设置到处理器中
33             th.setFormatter(fm)
34             # 将处理器添加到格式器中
35             cls.__logger.addHandler(th)
36         # 返回日志器
37         return cls.__logger
38 
39 if __name__ == '__main__':
40     log = GetLog.get_logger()
41     log.info("测试信息日志级别")
42     log.error("测试错误级别")

【Tips】

  • 在读取或存储相关数据到本项目下的文件夹中时(如读取测试数据/日志存储到指定目录下),由于由于路径中存在相同的前缀,因此我们可以将相同的前缀使用常量BASE_PATH进行统一管理,可以简化路径的书写(在项目根目录下的config.py模块中实现)
1 import os
2 
3 BASE_PATH = os.path.dirname(__file__)
  • 为防止使用pytest指令执行测试脚本时出现路径报错的问题,我们可以在__init__.py文件中添加如下配置信息:
    
    1 """
    2 用于解决路径报问题: 用于自动加载__init__.py文件所在目录下的模块
    3 """
    4 import sys
    5 import os
    6 
    7 sys.path.append(os.getcwd())

【报错信息如下】

七、测试脚本的执行及在线生成测试报告

在执行测试脚本之前,我们需要通过调试确保每个测试脚本都能独立的正常运行。

  • 配置文件的编写
    • 位置:放置在项目的根目录下
    • 名称:pytest.ini
    • 内容如下:

1 [pytest]
2 addopts = -s --alluredir report
3 testpaths = ./scripts
4 python_files = test*
5 python_classes = Test*
6 python_functions = test*

  • 测试脚本的执行
    • 由于pytest在执行测试脚本时,是按照.py模块名称的ACSII顺序进行执行的,因此在给测试脚本命名时,处理以test开头外,可以人为的添加_a_、_b_等字母,使测试脚本按预期的顺序执行; 
    • 在Terminal中输入:pytest 
  • 在线生成测试报告
    • allure serve report

至此,我们完成了Api自动化测试框架的搭建,当我们在搭建接口自动化测试框架时,只需要遵循如下原则即可:

  • 项目目录结构搭建  -- api、scripts、tool、data、report、log
  • api资源结构的搭建
    • 公共变量的抽取  -- 存储在api下的__init__.py模块中
    • 初始化 -- 定义接口url
    • 接口封装 -- 暂时使用pass进行占位
  • api资源结构的实现
    • 定义请求数据
    • 发送请求获取服务器返回的响应对象
  • 测试结构搭建
    • 初始化  -- 获取apiXX对象
    • 接口测试方法 -- 暂时使用pass进行占位
  • 测试结构实现
    • 调用对应api资源中的接口封装方法
    • 参数化
    • 断言

Python接口自动化测试零基础入门到精通(2023最新版)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值