4步学会接口自动化测试

🍅 视频学习:文末有免费的配套视频可观看

🍅 关注公众号【互联网杂货铺】,回复 1 ,免费获取软件测试全套资料,资料在手,涨薪更快

一、简介

本文从一个简单的登录接口测试入手,一步步调整优化接口调用姿势;
然后简单讨论了一下接口测试框架的要点;
最后介绍了一下我们目前正在使用的接口测试框架 pithy。
期望读者可以通过本文对接口自动化测试有一个大致的了解。

在这里插入图片描述

二、引言

为什么要做接口自动化测试?

在当前互联网产品迭代频繁的背景下,回归测试的时间越来越少,很难在每个迭代都对所有功能做完整回归。

但接口自动化测试因其实现简单、维护成本低,容易提高覆盖率等特点,越来越受重视。

为什么要自己写框架呢?

使用 requets + unittest 很容易实现接口自动化测试,而且 requests 的api已经非常人性化,非常简单。

但通过封装以后(特别是针对公司内特定接口),再加上对一些常用工具的封装,可以进一步提高业务脚本编写效率。

三、环境准备

确保本机已安装 python2.7 以上版本,然后安装如下库:

pip install flask
pip install requests

后面我们会使用 flask 写一个用来测试的接口,使用requests去测试。

四、测试接口准备

下面使用 flask 实现两个 http 接口,一个登录,另外一个查询详情,但需要登录后才可以,新建一个 demo.py 文件(注意,不要使用windows记事本),把下面代码 copy 进去,然后保存、关闭。

接口代码:

#!/usr/bin/python# coding=utf-8from flask import Flask, request, session, jsonifyUSERNAME = 'admin'PASSWORD = '123456'app = Flask(__name__)
app.secret_key = 'pithy'@app.route('/login', methods=['GET', 'POST'])def login():error = Noneif request.method == 'POST':        if request.form['username'] != USERNAME:error = 'Invalid username'elif request.form['password'] != PASSWORD:error = 'Invalid password'else:session['logged_in'] = Truereturn jsonify({'code': 200, 'msg': 'success'})    return jsonify({'code': 401, 'msg': error}), 401@app.route('/info', methods=['get'])def info():if not session.get('logged_in'):        return jsonify({'code': 401, 'msg': 'please login !!'})    return jsonify({'code': 200, 'msg': 'success', 'data': 'info'})if __name__ == '__main__':app.run(debug=True)

最后执行如下命令:

python demo.py

响应如下:

* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)* Restarting with sta

大家可以看到服务已经起来了。

接口信息

登录接口

请求url

/login

请求方法

post

请求参数

| 参数名称 | 参数类型 | 参数说明 |

| :————: | :——-: | :——: |

| username | String | 登录名称 |

| password | String | 登录密码 |

响应信息

| 参数名称 | 参数类型 | 参数说明 |

| :————: | :——-: | :——: |

| code | Integer | 结果code |

| msg | String | 结果信息 |

详情接口

请求url

/info

请求方法

get

请求 cookies

| 参数名称 | 参数类型 | 参数说明 |

| :————: | :——-: | :——: |

| session | String | session |

响应信息

| 参数名称 | 参数类型 | 参数说明 |

| :————: | :——-: | :——: |

| code | Integer | 结果code |

| msg | String | 结果信息 |

| data | String | 数据信息 |

五、编写接口测试

测试思路

使用 requests库模拟发送 HTTP 请求。
使用 python 标准库里 unittest 写测试 case。

脚本实现:

#!/usr/bin/python# coding=utf-8import requestsimport unittestclass TestLogin(unittest.TestCase):@classmethoddef setUpClass(cls):cls.login_url = 'http://127.0.0.1:5000/login'cls.info_url = 'http://127.0.0.1:5000/info'cls.username = 'admin'cls.password = '123456'def test_login(self):"""测试登录"""data = {            'username': self.username,            'password': self.password}response = requests.post(self.login_url, data=data).json()        assert response['code'] == 200assert response['msg'] == 'success'def test_info(self):"""测试info接口"""data = {            'username': self.username,            'password': self.password}response_cookies = requests.post(self.login_url, data=data).cookiessession = response_cookies.get('session')        assert sessioninfo_cookies = {            'session': session}response = requests.get(self.info_url, cookies=info_cookies).json()        assert response['code'] == 200assert response['msg'] == 'success'assert response['data'] == 'info'

六、优化

封装接口调用

写完这个测试登录脚本,你或许会发现,在整个项目的测试过程,登录可能不止用到一次,如果每次都这么写,会不会太冗余了?

对,确实太冗余了,下面做一下简单的封装,把登录接口的调用封装到一个方法里,把调用参数暴漏出来,示例脚本如下:

#!/usr/bin/python# coding=utf-8import requestsimport unittesttry:    from urlparse import urljoinexcept ImportError:    from urllib.parse import urljoinclass DemoApi(object):def __init__(self, base_url):self.base_url = base_url    def login(self, username, password):"""登录接口:param username: 用户名:param password: 密码"""url = urljoin(self.base_url, 'login')data = {            'username': username,            'password': password}        return requests.post(url, data=data).json()    def get_cookies(self, username, password):"""获取登录cookies"""url = urljoin(self.base_url, 'login')data = {            'username': username,            'password': password}        return requests.post(url, data=data).cookies    def info(self, cookies):"""详情接口"""url = urljoin(self.base_url, 'info')        return requests.get(url, cookies=cookies).json()class TestLogin(unittest.TestCase):@classmethoddef setUpClass(cls):cls.base_url = 'http://127.0.0.1:5000'cls.username = 'admin'cls.password = '123456'cls.app = DemoApi(cls.base_url)    def test_login(self):"""测试登录"""response = self.app.login(self.username, self.password)        assert response['code'] == 200assert response['msg'] == 'success'def test_info(self):"""测试获取详情信息"""cookies = self.app.get_cookies(self.username, self.password)response = self.app.info(cookies)        assert response['code'] == 200assert response['msg'] == 'success'assert response['data'] == 'info'

OK,在这一个版本中,我们不但在把登录接口的调用封装成了一个实例方法,实现了复用,而且还把 host(self.base_url)提取了出来。

但问题又来了,登录之后,登录接口的 http 响应会把 session 以 cookie 的形式 set 到客户端,之后的接口都会使用此 session 去请求。

还有,就是在接口调用过程中,希望可以把日志打印出来,以便调试或者出错时查看。

好吧,我们再来改一版。

保持 cookies &增加 log 信息

使用 requests 库里的同一个 Session 对象 (它也会在同一个 Session 实例发出的所有请求之间保持 cookie ),即可解决上面的问题,示例代码如下:

#!/usr/bin/python# coding=utf-8import unittestfrom pprint import pprintfrom requests.sessions import Sessiontry:    from urlparse import urljoinexcept ImportError:    from urllib.parse import urljoinclass DemoApi(object):def __init__(self, base_url):self.base_url = base_url        # 创建session实例self.session = Session()    def login(self, username, password):"""登录接口:param username: 用户名:param password: 密码"""url = urljoin(self.base_url, 'login')data = {            'username': username,            'password': password}response = self.session.post(url, data=data).json()print('\n*****************************************')print(u'\n1、请求url: \n%s' % url)print(u'\n2、请求头信息:')pprint(self.session.headers)print(u'\n3、请求参数:')pprint(data)print(u'\n4、响应:')pprint(response)        return response    def info(self):"""详情接口"""url = urljoin(self.base_url, 'info')response = self.session.get(url).json()print('\n*****************************************')print(u'\n1、请求url: \n%s' % url)print(u'\n2、请求头信息:')pprint(self.session.headers)print(u'\n3、请求cookies:')pprint(dict(self.session.cookies))print(u'\n4、响应:')pprint(response)        return responseclass TestLogin(unittest.TestCase):@classmethoddef setUpClass(cls):cls.base_url = 'http://127.0.0.1:5000'cls.username = 'admin'cls.password = '123456'cls.app = DemoApi(cls.base_url)    def test_login(self):"""测试登录"""response = self.app.login(self.username, self.password)        assert response['code'] == 200assert response['msg'] == 'success'def test_info(self):"""测试获取详情信息"""self.app.login(self.username, self.password)response = self.app.info()        assert response['code'] == 200assert response['msg'] == 'success'assert response['data'] == 'info'

大功告成,我们把多个相关接口调用封装到一个类中,使用同一个 requests Session 实例来保持 cookies,并且在调用过程中打印出了日志,我们所有目标都实现了。

但再看下脚本,又会感觉不太舒服,在每个方法里,都要写一遍print 1、2、3… 要拼url、还要很多细节等等。

但其实我们 真正需要做的只是拼出关键的参数(url 参数、body 参数或者传入 headers 信息),可不可以只需定义必须的信息,然后把其它共性的东西都封装起来呢,统一放到一个地方去管理?

在这我为大家准备了一份软件测试视频教程(含面试、接口、自动化、性能测试等),就在下方,需要的可以直接去观看,也可以直接【点击文末小卡片免费领取资料文档】

【2024年最新版】字节大佬一周讲完的自动化测试教程,挑战15天学完就业,从入门到实战,少走99%的弯路!

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

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

相关文章

C++ 实战项目之 Boost 搜索引擎

项目地址:https://gitee.com/Vertas/boost-searcher-project 1. 项目背景 日常生活中我们使用过很多搜索引擎,比如百度,搜狗,360搜索等。我们今天是要实现一个像百度这样的搜索引擎嘛?那是不可能的,因为像…

视频编解码技术介绍 - 基本概念篇

第一章 视频编解码技术介绍 - 基本概念篇 文章目录 前言1. 我的疑问1.1 什么是视频编解码技术1.2 为什么会有视频编解码技术1.3 视频编解码中有哪些核心技术1.4 作为开发者需要重点了解视频编解码中的哪些技术 2. 视频编解码的历史3. 基本概念3.1 像素3.2 分辨率3.3 ppi(像素密…

学历双非,找中小厂测试行不行

大家好,我是洋子。今年的24春招大部分互联网公司都启动了,25届实习生招聘也同步启动。 虽然就业市场看起来还是比较严峻,但值得欣慰的是大厂招聘hc确有回暖迹象,腾讯2024年招聘实习生5000,美团24春招&25转正实习hc…

混凝土建筑物墙面缺陷数据集

混凝土建筑物墙面缺陷数据集,1900多张图像,包含墙体裂缝和剥落两类,仅有图片无标注 适用于CV项目,毕设,科研,实验等 需要此数据集或其他任何数据集请私信

iOS——【自动引用计数】ARC规则及实现

1.3.3所有权修饰符 所有权修饰符一共有四种: __strong 修饰符__weak 修饰符__undafe_unretained 修饰符__autoreleasing 修饰符 __strong修饰符 _strong修饰符表示对对象的强引用,持有强引用的变量在超出其作用域的时候会被废弃,随着强引…

LLM之RAG实战(二十八)| 探索RAG query重写

在检索增强生成(RAG)中,我们经常遇到用户原始查询的问题,如措辞不准确或缺乏语义信息,比如“The NBA champion of 2020 is the Los Angeles Lakers! Tell me what is langchain framework?”这样的查询,如…

【GAMES101】Lecture04 Transformation Cont. 变换 续集

目录 0 引言1 3D Transformations1.1 缩放和平移变换1.2 旋转变换1.3 Quat 四元数 2 Viewing Transformation 观测变换2.1 View(视图)/ Camera Transformation 视图变换2.1.1 什么是视图变换2.1.2 如何进行视图变换2.1.3 总结 2.2 Projection&#xff08…

【广度优先搜索】【图论】【并集查找】2493. 将节点分成尽可能多的组

作者推荐 视频算法专题 本文涉及知识点 广度优先搜索 图论 并集查找 LeetCod2493. 将节点分成尽可能多的组 给你一个正整数 n ,表示一个 无向 图中的节点数目,节点编号从 1 到 n 。 同时给你一个二维整数数组 edges ,其中 edges[i] [ai…

音视频学习笔记——实现PCM和H264合成MP4功能

本文主要记录实现PCM和H264合成MP4功能的整个框架&#xff0c;各个模块中FFmpeg的api使用流程&#xff0c;便于后续学习和复盘。 本专栏知识点是通过<零声教育>的音视频流媒体高级开发课程进行系统学习&#xff0c;梳理总结后写下文章&#xff0c;对音视频相关内容感兴趣…

智能指针基础知识【C++】【RAII思想 || unique_ptr || shared_ptrweak_ptr || 循环引用问题】

目录 一&#xff0c;为什么需要智能指针 二&#xff0c;内存泄露的基本认识 1. 内存泄露分类 2. 常见的内存检测工具 3&#xff0c;如何避免内存泄露 三&#xff0c;智能指针的使用与原理 1. RAII思想 2. 智能指针 &#xff08;1. unique_ptr &#xff08;2. shared_…

[MYSQL]当数据库被攻破如何重新恢复

前情提要&#xff1a;mysql数据库默认密码、默认端口没有改&#xff0c;也没做安全防护&#xff0c;导致被攻破被索要比特币。 那我们自然是不能给他们的&#xff0c;下面罗列我的补救方法。 密码修改相关 第一步大家自然都会想到先去修改密码&#xff1a; mysqladmin -u roo…

二维码门楼牌管理系统应用场景:商业与零售业发展的助推器

文章目录 前言一、二维码门楼牌管理系统的基本功能二、商业和零售业中的应用场景三、二维码门楼牌管理系统的优势分析四、结论 前言 在数字化时代的浪潮中&#xff0c;二维码门楼牌管理系统凭借其独特的优势&#xff0c;正在逐步成为商业和零售业发展的新宠。它不仅能够为商家…