一个项目带你走进接口自动化测试

news/2024/4/30 3:04:02/文章来源:https://blog.csdn.net/Uncle_wangcode/article/details/127016153

文章目录

  • 前言
  • 一、项目环境搭建
  • 二、项目分析
  • 三、框架搭建
      • 1、解决登录问题、获取token
      • 2、熟悉项目的接口请求方式、二次封装requests请求
      • 3、缓解业务请求接口参数臃肿
      • 4、重新封装logging日志
      • 5、通用方法编写
  • 四、编写自动化脚本
      • 场景业务需求
      • 单接口业务需求
  • 五、生成测试报告
  • 六、写在最后


前言

  • 该项目有助于进一步了解自动化测试

  • 适用于普遍中型企业接口自动化框架

    • Python+Request+Pytest+Yaml+Log+allure+git+邮箱/钉钉+集成Jenkins(本文暂时不写集成Jenkins)
  • 适合有一定Python编程语言基础,了解函数式编程;会使用Pycharm开发工具。


一、项目环境搭建

~~为了方便同学们进一步了解接口自动化测试,该项目基于考试星在线考试系统进行接口自动化测试。

在这里插入图片描述

  • 提前注册账号

  • 熟悉里面的问卷模块业务功能(玩玩!)

    • 发布问卷
    • 查询问卷
    • 删除问卷

二、项目分析

  1. 解决项目登录问题(Cookie持久化)、部分请求操作包含token(获取token)
  2. 知道项目主要接口请求类型,便于requests请求二次封装
  3. 如何处理数据(YAML)
  4. 如何记录日志(Logging)
  5. 通用方法剥离
  6. 生成测试报告(Allure)-该博客省略
  7. 如何发生测试报告(集成邮箱/钉钉)-该博客省略
  8. 如何持续集成(Jenkins)-该博客省略

三、框架搭建

在这里插入图片描述

1、解决登录问题、获取token

	打开F12抓取登录等接口,分析请求方式、请求体内容、返回值内容login 接口可以获取Cooke值,获取存储即可cookie持久化操作login_check 接口返回值中有token值,即发起请求(两个参数sessionid和companyId都是login接口返回中有)即可获取

在这里插入图片描述

# -*- encoding:utf-8 -*-
__author__ = "Nick"
__created_date__ = "2022/09/24"import requests
import urllib3
import jsonHTTP_HEADERS = {'authority': "www.kaoshixing.com",'pragma': "no-cache",'Cache-Control': "no-cache",'origin': "https://www.kaoshixing.com",'user-agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36",'x-tingyun-id': "YfNlX9ebdkc;r=778649428",'Content-Type': "application/x-www-form-urlencoded;charset=UTF-8",'accept': "application/json, text/javascript, */*; q=0.01",'sec-fetch-dest': "empty",'x-requested-with': "XMLHttpRequest",'sec-fetch-site': "same-origin",'sec-fetch-mode': "cors",'referer': "https://www.kaoshixing.com/login/account/login/262319",'accept-language': "zh-CN,zh;q=0.9",}class Exam_login(object):"""考试星登录方法这里只考虑单账号登录,只把user_name参数化@param user_name 用户名companyIdnewCompanyIdpasswordpasswordMD5 这些参数通过抓取Login接口即可获得"""def __init__(self,user_name):self.user_name = user_name# 处理user_name_input 参数user_name_input = user_name.split('@')[0]login_url = "https://www.kaoshixing.com/login/account/login"data = {"userName": user_name,"userNameInput": user_name_input,"phoneAccount": "","authCode": "","captchaText": "","companyId": "xxxx","newCompanyId": "xxxx","password": "xxxx","passwordMD5": "xxxx","nextUrl": "","remember": "false"}# 警用urllib3 警告urllib3.disable_warnings()response = requests.post(login_url, data=data, headers=HTTP_HEADERS, verify=False)# 获取登录后的cookieself.cookies = requests.utils.dict_from_cookiejar(response.cookies)# session_id 用于登录login_checkself.session_id = self.cookies['sessionId']# 把获取的cookie值进行拼接cookie = ""for i in self.cookies:cookie = cookie + i + '=' + self.cookies[i] + ';'# 把获取的cookie与本地存储的cookie进行拼接self.cookies = cookiecookies = cookie + config.LOCAL_COOKIEself.post_cookies = cookiedef login_check(self):"""考试星登录后验证方法companyId Login接口抓取"""login_check_url = "https://exam.kaoshixing.com/login/public/login_check"data ={"sessionId": self.session_id,"companyId": "xxxx"}# 转为字符串进行传参数data = json.dumps(data)response = requests.request("POST", login_check_url, headers=HTTP_HEADERS, data=data, verify=False)content = json.loads(str(response.content,encoding='utf-8'))# 获取登录token的值token = content['data']['bizContent']['token']return tokenif __name__ == '__main__':a  = Exam_login(user_name="xxxx")print(a.post_cookies)token = a.login_check()print(token)

2、熟悉项目的接口请求方式、二次封装requests请求

  • 项目中主要是post和get请求,post请求居多
import requestsdef exam_request(method, param, headers, url):"""考试星接口二次封装,考试星大部分是POST请求:param method: 请求方法:param param: 参数:param headers: 请求头:param url: 请求地址:return: 数据"""if len(param)<= 0:raise AssertionError("参数不能为空")# 如果是get请求,拼接urlif method == "GET" or  method == "get":get_param = ""for key in param:get_param = get_param + "{}={}&".format(key, param[key])url = url + "?" + get_parampayload = {}response = requests.request("GET", url, headers=headers, data=payload)else:response = requests.request("POST", url, headers=headers, data=param)return response

3、缓解业务请求接口参数臃肿

# -*- encoding:utf-8 -*-
__author__ = "Nick"
__created_date__ = "2022/09/24""""用来读取数据"""import yaml 
import json
from configparser import  ConfigParserclass MyConfigParser(ConfigParser):# 重写configparser 中的optionxform 函数 解决.ini 文件自动转小写的问题def __init__(self, defaults=None):ConfigParser.__init__(self, defaults=defaults)def optionxform(self, optionstr: str) -> str:return optionstrclass ReadFileData():def __init__(self):pass# 读取Yaml数据def load_yaml(self, file_path):with open(file_path, encoding="utf-8") as f:data = yaml.safe_load(f)return data# 读取json数据def load_json(self, file_path):with open(file_path, encoding="utf-8") as f:data = json.load(f)return data# 读取init数据def load_init(self, file_path):config = MyConfigParser()config.read(file_path, encoding="utf-8")data = dict(config._sections)return  datadata = ReadFileData()
# -*- encoding:utf-8 -*-
__author__ = "Nick"
__created_date__ = "2022/09/24"import pytest
import  os
from method.read_data import data # 上一个封装读取数据的py文件路径BASE_PATH = os.path.dirname(__file__)def get_data(yaml_file_name):try:data_file_path = os.path.join(BASE_PATH, "data", yaml_file_name)yaml_data = data.load_yaml(data_file_path)except Exception as e:pytest.skip(str(e))else:return yaml_dataapi_data_get = get_data("api_test_get.yaml") # 读取当前目录data下文件名为api_test_get.yaml
api_data_post = get_data("api_test_post.yaml")# 读取当前目录data下文件名为api_test_post.yaml
scenes_data = get_data("scenes_test.yaml")#读取当前目录data下文件名为scenes_test.yaml
单接口参数通过@pytest.mark.parametrize()传递参数即可,场景测试参数需要写个模块级别的请求fixtures
"""
针对于单接口  
yaml数据为
test_right:# 考试口令,返回码- ['EDBHET', 0]
"""from Test_exam.conftest import api_data_getclass Test_get_demo():"""获取考试列表"""@allure.testcase(".....")@allure.description("test_get_demo")@pytest.mark.parametrize("name, result",api_data_get["test_get_demo"])def test_get_demo(self,name, result):
"""
对于场景,Yaml参数为
# 新建我的考试文件夹-重命名-移动文件夹-删除
test_create_dir_rename_move_delete:# 创建考试名称new_name: '期中考试'# 修改考试名称change_name: '期末考试'# 移动文件夹idtarget_id: '15688454'# 删除返回断言errorcode: 0
"""def test_create_dir_rename_move_delete(testcase_data):pass

4、重新封装logging日志

# -*- encoding:utf-8 -*-
__author__ = "Nick"
__created_date__ = "2022/09/24""""
封装log日志控制台打印输出
"""import datetime
import logging
import osdef init_log(log_level=logging.INFO, log_dir =''):if log_dir =='':logging.basicConfig(level=log_level,format="%(asctime)s-%(name)s-%(levelname)s-%(message)s",datefmt= '%m-%d %H:%M:%S')# 此处省略文件记录日志方法方法def debug(tag, msg):_logger = logging.getLogger(tag)_logger.debug(msg)def info(tag, msg):_logger = logging.getLogger(tag)_logger.info(msg)def warning(tag, msg):_logger = logging.getLogger(tag)_logger.warning(msg)def error(tag, msg):_logger = logging.getLogger(tag)_logger.error(msg)def critical(tag, msg):_logger = logging.getLogger(tag)_logger.error(msg)init_log()

5、通用方法编写

  • 创建13时间戳
  • 生成Allure测试报告

四、编写自动化脚本

场景业务需求

  • 管理员创建问卷->列表查询问卷->用户答卷提交->获取用户问卷信息->删除问卷
  • 问卷分类新增->修改->删除
# -*- encoding:utf-8 -*-
__author__ = "Nick"
__created_date__ = "2022/09/24"from method.exam_request import Exam_request
from method import config
import allure
import pytest@allure.description("创建分类_修改分类_删除分类")
@allure.title("test_create_category_change_and_delete")
def test_create_category_change_and_delete(testcase_data):# 实例化request = Exam_request()# 登录账号request.account_login(user_name=config.MASTER_ACCOUNT)# 获取分类idrequest.get_classify_id()assert request.pid is not None# 新增分类name = testcase_data["name"]request.add_classify(name)assert request.question_classify_id is not None# 修改分类rename = testcase_data["rename"]update_info = request.update_classify(rename=rename)assert update_info["code"] == 200# 删除分类delete_info = request.delete_classify()assert delete_info["code"] == 200if __name__ == '__main__':pytest.main([__file__,'-s'])
# -*- encoding:utf-8 -*-
__author__ = "Nick"
__created_date__ = "2022/09/24"from method.exam_request import Exam_request
from method import config
import allure
import pytest@allure.description("创建问卷_查询问卷_用户答卷_获取数据_删除问卷")
@allure.title("test_create_questionnaire_query_user_post_get_data_delete_questionnaire")
def test_create_questionnaire_query_user_post_get_data_delete_questionnaire(testcase_data):# 实例化request = Exam_request()# 登录账号request.account_login(user_name=config.MASTER_ACCOUNT)# 编辑问卷name = testcase_data["name"]introduce = testcase_data["introduce"]question = testcase_data["question"]content = testcase_data["content"]request.edit_the_questionnaire(name=name,introduction=introduce,question=question,content=content)assert request.questioninfotab is not Noneassert request.questioninfo is not None# 发布问卷days = testcase_data["during_days"]request.post_questionnaire(title=name,during_time=days)# 查询问卷question_info = request.query_questionnaire(name=name)assert question_info["code"] == testcase_data["code"]assert question_info["data"]["bizContent"]["rows"][0]["title"] == name# 获取问卷request.get_questionnaire()assert request.questionid is not None# 提交问卷request.submit_questionnaire()# 统计数据request.analysis_questionnaire()# 删除问卷---去了回收站,并未删除request.delete_questionnaire()assert request.code == 200if __name__ == '__main__':pytest.main([__file__,'-s'])

单接口业务需求

  • 存在问卷删除
  • 不存在问卷删除
# -*- encoding:utf-8 -*-
__author__ = "Nick"
__created_date__ = "2022/09/24""""
这里的两个删除只是例子,虽然不影响功能
但任意id值都可以删除,接口并未做校验
"""import pytest
import allure
import os
from method.exam_request import Exam_request
from method import config
from Test_exam.conftest import api_data_getclass Test_delete_questionnaire():"""删除问卷接口"""@allure.testcase("删除问卷接口-存在")@allure.description("Test_delete_questionnaire")@pytest.mark.parametrize("id, code",api_data_get["test_delete_one"])def test_delete_one(self,id, code):# 初始化request = Exam_request()# 登录账号request.account_login(user_name=config.MASTER_ACCOUNT)# 删除问卷request.delete_questionnaire(id,single=True)assert request.code == code@allure.testcase("删除问卷接口-不存在")@allure.description("Test_delete_questionnaire")@pytest.mark.parametrize("id, code",api_data_get["test_delete_two"])def test_delete_two(self,id, code):# 初始化request = Exam_request()# 登录账号request.account_login(user_name=config.MASTER_ACCOUNT)# 删除问卷request.delete_questionnaire(id, single=True)assert request.code == codeif __name__ == '__main__':pytest.main([__file__ ,'-s'])# 单脚本测试生成allure报告# pytest.main([__file__, '-s', '-q', '--alluredir', './result'])# os.system('allure generate ./result -o ./report --clean')

五、生成测试报告

  • 自行配置allure环境(windows/mac)
# 定义生成测试报告的方法
def create_allure_report(xml_report_path, html_report_path):"""生成Allure测试报告"""# 自定义shellcmd = "allure generate %s -o %s --clean"%(xml_report_path, html_report_path)try:os.system(cmd)except Exception:raise Exception("执行用例失败,请检查环境配置")

在这里插入图片描述

六、写在最后

  • 文档主要是带入了解接口自动化的学习(基于Python语言),有些细化的知识点需要自己去索引学习
  • 有部分过程文档没有写,需要自己去研究,最后会附上整体项目源码(知识星球内可下载)
  • 集成Jenkins也不是特别难,搭建好Jenkins自己捣鼓捣鼓即可集成,下次有时间把Jenkins集成补充完成

在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_13300.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CSDN线上竞赛编程第六期参赛心得

CSDN编程竞赛报名地址&#xff1a;https://edu.csdn.net/contest/detail/16 &#xff08;请不要删掉此地址&#xff09; CSDN线上竞赛编程第六期参赛心得前言/背景大赛简介参赛流程参赛经历解题思路1、题目名称&#xff1a;严查枪火2、题目名称&#xff1a;鬼画符门3、题目名称…

HDMI/DVI____TMDS编码

一.编码步骤:基本方法:取第一位数据为初值,接下来输入的每一位与前一导出的位(根据判断条件)进行异或XOR或者同或XNOR(最小化传输);最后选择性反转这9bit数据(DC平衡处理)。 ①DE为高电平时,对8位RGB数据编码,第9bit表示采用了XOR / XNOR ,第10bit表示是否翻转。 …

04代码

import datetime #定义一个列表 mot=["今天星期一:\n坚持下去不是因为我很坚强,而是因为我别无选择。","今天星期二:\n含泪播种的人一定能笑着收获。","今天星期三:\n作对的事情比把事情做对更重要。","今天星期四:\n命运给予我们的不是失…

【NLP】自然语言处理的序列建模

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

Teams Bot App 初探

上一篇文章深入讲了incoming webhook。这篇文章我们来看一个稍微复杂点的&#xff0c;正式点的 teams app&#xff1a;bot。 我们先来和之前一样&#xff0c;通过teams toolkit 的 sample gallery来创建一个 Teams bot app。 创建之后我们先来看一下目录结构和生成的文件。 一…

二叉树中求最大路径和

题目来自LeetCode中&#xff0c;链接为124. 二叉树中的最大路径和 一棵树的最大路径和可能存在于哪里&#xff1a; 单纯的存在于以左子树为根节点的子树中单纯的存在于以右子树为根节点的子树中根节点到达左子树B中某节点的路径根节点到达右子树C中某节点的路径左子树中某节…

Android日志分析02-am篇

Android日志分析02-am篇 在日常分析bug时&#xff0c;免不了和系统ActivityManagerService打交道&#xff0c;根据日志去查看各个Activity的生命周期&#xff0c;从而判断是否出现Activity生命周期异常。 先使用adb logcat和adb bugreport再pixel2的模拟器抓取一份从开机到打开…

代码随想录4——链表: 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、面试题02.07链表相交、142.环形链表II

文章目录1.24两两交换链表中的节点1.1.题目1.2.思路1.3.代码实现1.3.1.对next指针的理解1.3.2.编程中要备份哪些节点的指针&#xff1f;1.3.3.代码实现2.19删除链表的倒数第N个节点2.1.题目2.2.思路3.面试题02.07链表相交3.1.题目3.2.解答4.142.环形链表II4.1.题目4.2.思路1.24…

JavaEE——No.1 多线程案例

JavaEE传送门JavaEE JavaEE——No.1 线程安全问题 JavaEE——No.2 线程安全问题 目录多线程案例1. 单例模式饿汉模式懒汉模式2. 阻塞队列阻塞队列的使用阻塞队列的实现多线程案例 1. 单例模式 单例模式是一种常见的设计模式. 设计模式: 软件开发时, 会遇到一些常见的 “问…

存储系统基本概念

内容框图 存储器的层次化结构 由于cpu运行太快&#xff0c;所以中间需要主存&#xff0c;Cache&#xff0c;寄存器去传递。 主存–辅存&#xff08;硬件操作系统&#xff09;&#xff1a;实现虚拟存贮系统&#xff0c;解决了主存容量不够的问题。 Cache–主存&#xff08;硬件自…

测试用例设计专栏

哈喽大家好哎呀&#xff0c;今天给大家普及一下测试用例如何设计&#xff0c;看牛逼的大佬们是如何测试的。 测试用例笔试题 出题&#xff1a;在一个页面上有一个输入框&#xff0c;一个计数器(count)按钮&#xff0c;用于计算一个文本字符串中字母a出现的次数&#xff0c;请…

Linux 逻辑卷精简卷报错问题解决

一、 故障描述 现象1:oraclelog目录提示坏道信息,进行修复后执行删除文件操作,目录不可使用。 现象2:lsblk看到目录出现重复,并且有tmeta,tdata卷出现(图一) 现象3:message日志出现多目录报错,持续写入(图二) 图一 检查lv #lvs -a 看到多出的pmspare,tdata,tmeta…

VSCode 使用教程-9.Node运行js出现 Cannot use import statement outside a module的问题

前言 js中导入公共模块&#xff0c;使用import的方式导入&#xff0c;用node运行js文件会出现Cannot use import statement outside a module的问题 问题描述 目录结构 └─src└─js└─ext.js└─main.js └─index.html在ext.js 文件写一些公共方法 export const m (f…

vue3 ts vite 项目快速构建

1.安装nodejs(建议装14版本稳定) 下载 | Node.js 中文网 装完之后会有一个命令叫 npm 可以在终端输入npm -v 来检查是否安装成功2.构建vite项目官方文档开始 {#getting-started} | Vite中文网 vite 的优势冷服务 默认的构建目标浏览器是能 在 script 标签上支持原生 ESM 和…

Java操作HDFS

1. 创建maven项目 New Project 2. 添加依赖 <!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-client --><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-client</artifactId><version>2.…

steam搬砖汇率差项目详解

很久没有分享赚钱项目了&#xff0c;今天这里给大家介绍一个游戏搬砖的项目&#xff1a;steam游戏汇率差赚钱项目。 项目原理&#xff1a; Steam平台是一个国外游戏及装备售卖平台。而我们所谓的Steam游戏装备搬砖就是利用steam平台和网易的BUFF平台来操作。steam汇率差赚钱原…

十大经典排序算法综述(Java代码实现,思想通用)

关于十大排序的文章也有不少了&#xff0c;但感觉大部分在各个排序算法的适用场景、如何实现外排等细节方面没怎么讲&#xff0c;故总结了这篇文章&#xff0c;欢迎浏览 一、前言 内部排序是指排序时将待排序数据全部加载到内存的算法。 外部排序是指在处理海量数据排序时&…

什么是C语言?

什么是C语言&#xff1f; 文章目录什么是C语言&#xff1f;1.C语言的起源2.C语言的使用领域3. 为什么要学习C语言4.C语言的学习境界5.如何学习C语言6.学习C语言的推荐书籍1.C语言的起源 C语言之父是丹尼斯里奇&#xff1a;丹尼斯里奇&#xff08;1941年9月9日-2011年10月12日&…

Linux 简单命令 - cron 计划任务 、NTP

Linux 简单命令 - cron NTP cronNTP 一、cron 计划任务就是按照系统的时间(时刻、周期)执行指定的任务 系统服务&#xff1a; crond。 配置文件&#xff1a; /etc/crontab /var/spool/cron/用户名 配置记录格式&#xff1a; 分 时 日 月 周 任务操作命令 (用绝对路径、必要时…

集成学习详解

入门小菜鸟&#xff0c;希望像做笔记记录自己学的东西&#xff0c;也希望能帮助到同样入门的人&#xff0c;更希望大佬们帮忙纠错啦~侵权立删。 目录 一、集成学习的产生原因与相关定义 1、产生原因 2、相关定义 &#xff08;1&#xff09;同质集成 &#xff08;2&#xf…