目录
1. 需求分析
理解业务需求,若是针对未参与的项目实施接口自动化,应与业务人员、产品经理等沟通,了解接口所支持的业务场景和业务逻辑。根据业务需求,明确接口需要实现的具体功能,如数据的获取、修改、删除等操作,以及接口的输入输出要求。分析接口之间的依赖关系,确定接口的调用顺序和依赖条件。
2. 挑选接口
博客系统中接口较少,可以针对所有的接口实施自动化测试。
若是大型项目,可按照接口自动化流程中一挑选接口内容参考挑选
3. 设计测试用例
以博客系统为例
访问链接:
博客登陆页http://101.34.57.163:9090/blog_login.html博客系统登录账号密码:zhangsan/123456,lisi/123456
4. 设计自动化测试项目的架构
语言选择:python
技术栈:pytest框架、requests模块、PyYAML模块、jsonschema模块、allure-pytest模块、logging模块
集成开发环境:pycharm
├─2025_08_11_blog_ApiAutoTest
│ │ pytest.ini
│ │ requirements.txt
│ │ run.py
│ │
│ ├─allure_reports
│ │ │ app.js
│ │ │ favicon.ico
│ │ │ index.html
│ │ │ styles.css
│ │ │
│ │ ├─data
│ │ │ │ behaviors.csv
│ │ │ │ behaviors.json
│ │ │ │ categories.csv
│ │ │ │ categories.json
│ │ │ │ packages.json
│ │ │ │ suites.csv
│ │ │ │ suites.json
│ │ │ │ timeline.json
│ │ │ │
│ │ │ ├─attachments
│ │ │ │ 141a40ae59b0cf5e.txt
│ │ │ │ 15163ab9c50d8938.txt
│ │ │ │ 21c3c0ba361af7b5.txt
│ │ │ │ 23fa10e705a56745.txt
│ │ │ │ 2ca39162a83f16b7.txt
│ │ │ │ 2dd135369816b8b8.txt
│ │ │ │ 3fad6cda1aa685f1.txt
│ │ │ │ 47e9e74611eec6f3.txt
│ │ │ │ 51a0ae5b667b4297.txt
│ │ │ │ 58c3d73c1a315940.txt
│ │ │ │ 61fe05d5d81bbcb4.txt
│ │ │ │ 649206d1a0137587.txt
│ │ │ │ 677af8c3615fed7e.txt
│ │ │ │ 7706598fd5ed4960.txt
│ │ │ │ 7743b9dac35cdcea.txt
│ │ │ │ 7dd08bdeed3956fc.txt
│ │ │ │ 800219b86fc9af94.txt
│ │ │ │ 8f4170baaf64484f.txt
│ │ │ │ 9fe9be3d472349cb.txt
│ │ │ │ a6598f7ec096545f.txt
│ │ │ │ a74a31fc6a09dcd8.txt
│ │ │ │ ae34a4a45cca1131.txt
│ │ │ │ b367aebee411f180.txt
│ │ │ │ b47cebac4b2f2f7c.txt
│ │ │ │ c0bd97cdf0c667c6.txt
│ │ │ │ c32eb9842b0bb164.txt
│ │ │ │ ccf3cfc49b61b946.txt
│ │ │ │ dc969b63ca44b13c.txt
│ │ │ │ e936df907dc4ff43.txt
│ │ │ │ eb85cc1decf9f865.txt
│ │ │ │ f3cad2540e2226b9.txt
│ │ │ │ f6a0798c49af5159.txt
│ │ │ │ fb7a53d567fc1b54.txt
│ │ │ │ fb846cb16a9c54d0.txt
│ │ │ │
│ │ │ └─test-cases
│ │ │ 2098468ae17b2eb1.json
│ │ │ 28f7aa8c8d382cd6.json
│ │ │ 2a4fa81d3b9499e1.json
│ │ │ 2a6f16b8a23fd98.json
│ │ │ 2b8ad419805f5f81.json
│ │ │ 2c6612e74e6f6793.json
│ │ │ 2cf4f65f65a101d7.json
│ │ │ 31533d12f20ea402.json
│ │ │ 325253f6b43c8bc2.json
│ │ │ 3cb06e68371025b.json
│ │ │ 3e0d108648616b23.json
│ │ │ 43f879833b1a3661.json
│ │ │ 54839bcd96321669.json
│ │ │ 5ced0ccedf8c416e.json
│ │ │ 5dd9db88ed19c321.json
│ │ │ 6d1051609e557bb8.json
│ │ │ 786cea6c8ecfad97.json
│ │ │ 7dc26bc316607ffe.json
│ │ │ 8166cda3cabf11f3.json
│ │ │ 82d225c794345391.json
│ │ │ 89a8e3bc9ad1bfd2.json
│ │ │ 99d43f769da14072.json
│ │ │ a29bb8b30a2afa1a.json
│ │ │ a338768c1800708c.json
│ │ │ a33e7ec4a0a9cd50.json
│ │ │ a42dc4b6c47b5ecb.json
│ │ │ b422477dc000240e.json
│ │ │ cd67f355e590fe71.json
│ │ │ d52837cf81bce8ec.json
│ │ │ e66a04a5c91a1cb6.json
│ │ │ e7cac51cf511adb0.json
│ │ │ ebd24f207592fd20.json
│ │ │ f20a14ec23894bb4.json
│ │ │ fb1eae11d3637b94.json
│ │ │
│ │ ├─export
│ │ │ influxDbData.txt
│ │ │ mail.html
│ │ │ prometheusData.txt
│ │ │
│ │ ├─history
│ │ │ categories-trend.json
│ │ │ duration-trend.json
│ │ │ history-trend.json
│ │ │ history.json
│ │ │ retry-trend.json
│ │ │
│ │ ├─plugin
│ │ │ ├─behaviors
│ │ │ │ index.js
│ │ │ │
│ │ │ ├─packages
│ │ │ │ index.js
│ │ │ │
│ │ │ └─screen-diff
│ │ │ index.js
│ │ │ styles.css
│ │ │
│ │ └─widgets
│ │ behaviors.json
│ │ categories-trend.json
│ │ categories.json
│ │ duration-trend.json
│ │ duration.json
│ │ environment.json
│ │ executors.json
│ │ history-trend.json
│ │ launch.json
│ │ retry-trend.json
│ │ severity.json
│ │ status-chart.json
│ │ suites.json
│ │ summary.json
│ │
│ ├─allure_results
│ │ 00bed2a6-d198-4bff-a036-a60ba88a9150-result.json
│ │ 011bd74b-568c-4bee-a382-e61db1a2c974-attachment.txt
│ │ e9d5189b-5d06-4f6e-8fa4-e20a64849a8a-result.json
│ │ eb2d6c77-b719-4b0c-a321-9a96ba7e2958-result.json
│ │ /.........................
│ │ f90a5152-ff07-4e42-bb55-c95b7c4cfd56-result.json
│ │ f98c8230-ab2e-4358-acb4-e1f0458c50a8-attachment.txt
│ │ fc555fb0-ff7c-452b-a3f4-399781ef43a9-attachment.txt
│ │ fc6f2608-298e-4cd6-b344-7cafd330e24a-container.json
│ │ fdb5b0f9-c951-4c81-b2b1-8b0afc0d2f61-result.json
│ │ fe5163a6-8f49-42a1-87e0-9d6dddb4a38e-attachment.txt
│ │
│ ├─cases
│ │ │ test_add.py
│ │ │ test_detail.py
│ │ │ test_getAuthorInfo.py
│ │ │ test_getUserInfo.py
│ │ │ test_list.py
│ │ │ test_login.py
│ │ │ __init__.py
│ │ │
│ │ └─__pycache__
│ │ test_add.cpython-38-pytest-8.3.2.pyc
│ │ test_detail.cpython-38-pytest-8.3.2.pyc
│ │ test_getAuthorInfo.cpython-38-pytest-8.3.2.pyc
│ │ test_getUserInfo.cpython-38-pytest-8.3.2.pyc
│ │ test_list.cpython-38-pytest-8.3.2.pyc
│ │ test_login.cpython-38-pytest-8.3.2.pyc
│ │ __init__.cpython-38.pyc
│ │
│ ├─data
│ │ data.yml
│ │
│ ├─logs
│ │ 2025-08-11-err.log
│ │ 2025-08-11-info.log
│ │ 2025-08-11.log
│ │ 2025-08-12-err.log
│ │ 2025-08-12-info.log
│ │ 2025-08-12.log
│ │
│ └─utils
│ │ logger_util.py
│ │ request_util.py
│ │ yaml_util.py
│ │
│ └─__pycache__
│ logger_util.cpython-38.pyc
│ request_util.cpython-38.pyc
│ yaml_util.cpython-38.pyc
5. 编写代码
5.1 封装工具类/方法
5.1.1 封装请求
#utils/request_util.py
import logging
import requests
from utils.logger_util import logger
host = "http://101.34.57.163:9090/"
class Request:
log = logger.getlog()
def get(self,url,**kwargs):
self.log.info("准备发起get请求,url:"+url)
self.log.info("接口信息:{}".format(kwargs))
r = requests.get(url=url,**kwargs)
self.log.info("接口响应状态码:{}".format(r.status_code))
self.log.info("接口响应内容:{}".format(r.text))
return r
def post(self,url,**kwargs):
self.log.info("准备发起post请求,url:"+url)
self.log.info("接口信息:{}".format(kwargs))
r = requests.post(url=url,**kwargs)
self.log.info("接口响应状态码:{}".format(r.status_code))
self.log.info("接口响应内容:{}".format(r.text))
return r
5.1.2 封装yaml读取
#utils/yaml_util.py
'''
yaml相关的操作
'''
#往yaml文件中写入数据
import os
import yaml
#往yaml文件中写入数据
def write_yaml(filename,data):
with open(os.getcwd() + "/data/" + filename,mode="a+",encoding="utf-8") as f:
yaml.safe_dump(data,stream=f)
#读取yaml文件中的数据
def read_yaml(filename,key):
with open(os.getcwd() + "/data/" + filename,mode="r",encoding="utf-8") as f:
data = yaml.safe_load(f)
return data[key]
#情空
def clear_yaml(filename):
with open(os.getcwd()+ "/data/" + filename,mode="w",encoding="utf-8") as f:
f.truncate()
5.1.3 封装日志
#utils/logger_util.py
import logging
import os.path
import time
class infoFilter(logging.Filter):#继承
def filter(self,record):
return record.levelno == logging.INFO
class errFilter(logging.Filter):
def filter(self, record):
return record.levelno == logging.ERROR
class logger:
#获取日志对象 -- 定义类方法@classmethod
@classmethod
def getlog(cls):
#创建日志对象
cls.logger = logging.getLogger(__name__)
cls.logger.setLevel(logging.DEBUG)
# 保证logs文件夹必须创建好
LOG_PATH = "./logs/"
if not os.path.exists(LOG_PATH):
os.mkdir(LOG_PATH)
#将日志输出到日志文件中
'''
logs
2025-12-12.log
2025-12-12-info.log
2025-12-12-err.log
'''
# LOG_PATH = "/logs/"
now = time.strftime("%Y-%m-%d")
log_name = LOG_PATH + now + ".log"
info_log_name = LOG_PATH + now + "-info.log"
err_log_name = LOG_PATH + now + "-err.log"
#创建文件处理器
all_handler = logging.FileHandler(log_name,encoding="utf-8")
info_handler = logging.FileHandler(info_log_name,encoding="utf-8")
err_handler = logging.FileHandler(err_log_name,encoding="utf-8")
#创建处理器,将日志输出到控制台
streamHandler = logging.StreamHandler()
# 创建一个日子格式器对象
formatter = logging.Formatter(
"%(asctime)s %(levelname)s [%(name)s] [%(filename)s (%(funcName)s:%(lineno)d)] - %(message)s"
)
all_handler.setFormatter(formatter)
info_handler.setFormatter(formatter)
err_handler.setFormatter(formatter)
streamHandler.setFormatter(formatter)
#添加过滤器
info_handler.addFilter(infoFilter())#添加类对象
err_handler.addFilter(errFilter())#添加类对象
cls.logger.addHandler(all_handler)
cls.logger.addHandler(info_handler)
cls.logger.addHandler(err_handler)
#cls.logger.addHandler(streamHandler)
return cls.logger
5.2 用例编写
6. 执行测试用例
用例的执行顺序不是我们想要的,比如我们得先要登录,获取token,然后将用户凭证保存起来,给别的页面使用。
6.1 指定用户执行顺序
在使用pytest进行测试时,有时候我们需要按照特定的顺序来运行测试用例,尤其是在涉及到测试用例之间的依赖关系时。pytest本身并不直接支持通过配置来改变测试用例的默认运行顺序,pytest-order是一个第三方插件,专门用于控制测试用例的执行顺序。首先,你需要安装这个插件:
pip install pytest-order==1.3.0
既可以用在测试类上,也可以用在测试方法上,以测试类为例:
@pytest.mark.order(1)
def test_one():
assert True
@pytest.mark.order(2)
def test_two():
assert True
@pytest.mark.order(1)
class TestLogin:
#.....
@pytest.mark.order(2)
class TestList:
#.....
第二个执行结果:
7 生成测试报告并分析结果
- 测试时间:
测试执行时间从12:00:52持续到12:00:57,总共耗时5秒052毫秒。测试时间与测试用例数量成正比。用例数量越多,测试时间越长。通过优化测试脚本、并行执行和分布式测试环境,可以显著缩短测试时间。(比如多线程) - 测试用例总数:
共有34个测试用例,高测试用例总数通常表示测试覆盖范围广,能够更全面地验证接口功能;低测试用例总数可能意味着测试覆盖不全面,存在遗漏的风险。 - 通过率:
饼图显示了测试的通过率为100%,这意味着所有34个测试用例都成功执行,没有失败的测试用例。通过率是衡量接口质量和测试效果的关键指标。在测试环境中,通过率应达到95%以上