能力说明:
了解变量作用域、Java类的结构,能够创建带main方法可执行的java应用,从命令行运行java程序;能够使用Java基本数据类型、运算符和控制结构、数组、循环结构书写和运行简单的Java程序。
能力说明:
理解微服务架构与单体应用架构在开发模式与运维上的区别,了解分布式、容器、DevOps在微服务架构中的应用,理解微服务的设计原则与服务组件。了解Service Mesh概念与Istio基础知识。
一次偶然的机会,通过朋友的介绍,看到朋友们在群里聊起了在阿里云上针对博主有一个体验阿里的无影云桌面的机会,于是也申请了一个来体验一下。活动的地址如下:链接文字整个过程申请下来还是非常快的,从添加小助手的微信,帮我同步csdn上的文章到社区,不到一个工作日就帮我弄好了,然后我就可以联系工作人员开始申领一个云桌面体验一下了。之前在第一份工作的时候,在华为外包里面也使用过云桌面,当时给我的感觉就是:跟虚拟机差不多,出差什么的还得带一个绑定自己账号的小主机跑,接下来让我们一起来看一下阿里的无影云电脑使用起来怎么样。下面从测试的角度简单说一下一、申领的流程机器申领还是比较简单,小助手发送一个链接提交之后,就可以创建一个云主机。美中不足的是选择的云主机系统第一次确定之后就不可以更改,不过一般购买的云主机也都是不能再改类型,这一点也可以接受。整个申领的过程,操作还是比较简单,不用参考什么操作文档之类的,页面信息的录入和一些提示还是做得比较好。二、申请之后的使用1、首先提一点自己陷入的误区:一开始我认为无影云桌面应该就是跟阿里云一样的吧,那应该登录和使用方式应该在阿里云的app上就可以直接去使用吧,后来找了半天发现没找到入口,看了下文档,才发现,这个是要用单独的客户端才能去进行连接。2、创建用户,再分配云桌面,这个流程还是比较容易理解,云服务器本身就是支持多用户同时访问,比如,winserver的服务器,好像是支持同时两个用户一起访问吧 ,当时,在无影云上面,我没有去测试过到底支持多少人同时访问同一个云桌面,但是最起码用户的创建和分配 ,这个操作的流程还是符合用户的使用习惯 ,不用看文档也能轻易的找到入口,在这一点上,易用性还是可以。3、进入到桌面之后,第一件事情,当然是下载安装软件了,然后会发现使用centos系统的,软件应用市场各种报网络连接的问题,这种的话,是因为没有在外面配置网络 ,网络的话 ,申领服务器也会额外赠送一年的带宽可以用,购买的时候不用付费。但是要自己去购买。 够买完之后,发现应用市场如果加载还是有问题的话 (ubuntu软件:无法从“extensions.gnome.org”下载更新) ,搜索对应的报错,百度就可以解决 参考解决命令:sudo add-apt-repository ppa:gnome-shell-extensions/ppasudo apt-get updatesudo apt-get install gnome-shell-extensions执行完之后重启一下桌面比较好4、应用市场安装软件我申请的是centos的操作系统,默认是火狐浏览器,于是我在应用市场下载了一个谷歌浏览器,安装的时候需要输入administrator的密码,这个密码是啥???后来在钉钉群问小伙伴,发现可以直接用命令sudo passwd设置一个密码,到这里,软件可以正常安装,网络也可以正常访问了,一台崭新的电脑就这样诞生了。5、打开终端执行命令的时候,发现报“Syntax error: “(” unexpected”错误解决方法:输入 sudo dpkg-reconfigure dash ,然后在选项中选择No 即可 。这一点的话 ,在使用云桌面的时候要改一下,之前使用其他云桌面都不用改这些东西。然后接下来的话 ,就可以使用云服务器去部署自己的网站了,我这边部署了一个metersphere的测试平台,配置刚刚好符合平台的要求,部署好之后,运行了一下,效果还行,比公司服务器上部署的操作要快一点。6、比较好的一点,就是可以很方便的在自己电脑跟云服务器之间复制粘贴内容,这一点很方便。给一个大大的赞,未来在使用过程中发现更多好用的地方再同步给大家。整体来说体验还不错
1配置全局插件文件存放目录 说明:本地nodejs安装路径为:D:\Software\Nodejs 先在安装目录创建2个空的文件夹cd /d D:\Software\Nodejs mkdir node_cache mkdir node_global然后再执行以下命令:npm config set prefix "D:\Software\Nodejs\node_global" npm config set cache "D:\Software\Nodejs\node_cache" 2安装全局插件安装全局插件的好处的话,就是可以所有用户以及所有项目都共用这些插件。首先查看全局插件的安装存放目录的位置:npm root -g npm 全局安装插件:npm install module_name -g # -g参数表示全局安装执行命令安装一下cnpm、newman、vue的插件:npm install c npm -gnpm install newman -g npm install vue -g查看npm安装的全局插件列表:npm list -g 或者 npm ls -g3生产和开发环境依赖包的安装 这里主要来检验一下在安装环境过程中加上环境参数的时候,对package.json有什么区别:# 默认,安装的包是生产的依赖 npm install newman [--save|-S] # --save与-S等价 # 有部分插件,只有在本地调试的时候才会用到,比如代码检测插件ESLint npm install eslint [--save-dev|-D] # --save-dev与-S等价eslint 是一个代码检查的插件,类似sonarqube里面的打码扫描一样,像这种插件的话只需要本地使用,就可以用开发环境的进行依赖包安装。 4Npm的其他命令or用法 使用cnpm命令代替npm命令进行依赖包安装,加速下载插件npm install -g cnpm --registry=https://registry.npm.taobao.org cnpm install module_name指定镜像安装:npm install --registry=https://registry.npm.taobao.org设置代理 npm config set proxy http://username:password@server:port npm confit set https- proxy http://username:password@server:port删除代理 npm config delete proxy npm config delete https-proxy查看npm配置内容(可以配置默认指定源)npm config get registry或者查看配置文件 linux: ~/.npmrc windows:用户目录下的.npmrc 文件其他命令:# 提供一些其他命令供大家自己扩展学习了解(以下命令中的module_name要改为具体的包名) npm/cnpm view module_name version #查看某个包的最新版本 npm/cnpm view module_name versions #查看某个包的所有版本 npm uninstall module_name npm uninstall -g module_name今天的学习告一段落啦,如果在使用命令过程中遇到了问题,不要慌,可以copy报错内容百度一下,一般都能找到解决方法。 关注我,后续带你一起写页面,开发测试小工具,辅助提升测试效率。
1NPM环境安装npm环境搭建的话,需要安装Nodejs,可以打开百度首页输入nodejs进行搜索:具体安装这里可以参考之前写的文章:Node.js环境搭建以及常见npm用法注意事项:1、安装完之后,需要配置环境变量方可使用2、配置环境变量后,要重新打开一个新的cmd窗口,输入node -v 以及 npm -v 去验证下环境变量是否配置成功。(这里建议环境变量按照安装目录配置一个NODE_HOME,方便以后切换不同的版本)3、现在最新的版本比较高,但是不建议使用最新的版本,避免初学者在使用过程中遇到问题。2NPM的使用1、项目初始化操作在本地建一个空的文件夹,然后在当前路径下打开cmd窗口(在资源管理器中输入cmd即可):输入 npm init 即可初始化一个项目。输入命令后需要手动输入项目名、版本、描述信息、仓库地址等一系列的信息,部分可以直接敲回车跳过觉得繁琐的话,可以直接输入npm init -y ,则会采用默认的值进行初始化操作。执行完命令后,会生成一个package.json的文件,里面会有上述手动操作时需要输入的各项信息:2、安装js插件npm install 插件名@版本号比如:npm install element-ui安装过程中打印的一些黄色警告信息可以忽略。安装完成后,在文件夹中会多出一个node_modules文件夹以及一个package-lock.json的文件。package-lock.json是在执行npm install 命令的时候生成的一个文件,文件中会记录项目的名称、版本号以及相关的依赖信息等:package-lock.json文件的内容,有点类似于java里面maven工程的pom文件,对应的node_modules文件夹就类似使用maven的编译命令下载下来的依赖jar包存放的目录。3、插件版本不同格式说明在使用npm install 安装插件后,在package.json文件中,也会记录插件的版本号,细心的朋友可能会发现,版本前面带了一个^符号。符号说明^2.1.12表示大版本,后面的2.x.x表示次要版本号和小版本号是最新的。~2.1.2表示安装依赖的时候,安装的不一定是2.1.2的版本,而是2.1.x的最新版本。latest表示安装最新版本(不指定版本号安装时,默认是安装最新的版本)npm install element-ui@latest注意:指定版本安装时,对应的版本号必须存在喔,否则会报错。
为什么要写这篇文章呢? 最近看到群里有小伙伴在问问题,于是就有了这篇文章。仅仅站在自己的角度去分析一下。仅供参考!!!何为埋点?今天决定以自己的理解来简述一下埋点测试。我的理解,埋点其实就是在程序中的某个位置加一个标记,当用户触发到某个行为的时候,就采集一下数据,然后将数据上报到某个位置进行存储,埋点的最终目的是收集到相关的数据,用于给运营人员提供数据支撑等。 作为测试人员,测试埋点的功能有什么要注意的? 1、埋点的话,可以在前端埋点,也可以在后端埋点,测试前自己要了解埋点的具体需求,以及大致的流程是怎样操作的,比如哪些功能的操作会进行埋点,埋点之后的数据上报到何处,数据上报的频率是怎样。数据上报前是否还需要进行额外加工处理2、要注意埋点的业务规则,要核对是否多埋点、或者少上报的情况,另外,要重点关注上报的数据是否正确3、了解埋点上报的数据是对接的第三方平台还是自己公司自研的系统。 常见的一些埋点的场景 1、模块访问量、菜单点击量等这一类场景主要是记录一些数据,便于后续对产品进行优化和提供定向的数据运营支持。可能包括访问量、某个页面停留时长、浏览的页面数等,一种是页面统计,一种是操作行为统计。 个人觉得像你在淘宝app上搜索某一类商品,之后就会在各个电商平台上优先推荐你搜索过的同类型的数据,应该也是用到了埋点的技术。2、日志记录对于日志的记录,相信大家应该不会感到陌生。我觉得这也是埋点的一种应用场景。 埋点是不是随便点几下然后看看有没有数据就行? 个人认为,埋点的测试不算很难,但是也不是随便点几下然后看看数据就行。这里我想表达的是:有的时候,不能盲目的相信产品写的文档,作为一名优秀的测试人员,要敢于质疑产品写的文档。比如说,当你遇到不同的模块采集的数据记录的相关内容都一样的时候,那这个时候就需要去确认这样的记录是否合理,是否会影响到对后面的数据分析。 埋点的文档一般是怎样的? 翻遍了我的百宝箱,最终只找到下面这张图,供大家参考一下:埋点命名的备注供参考:1. 同样的行为,需要考虑发生的场景: 行为_场景2. 只可能在一个特定页面发生的行为:页面_行为以上是我对埋点测试的一点小小的理解,还想看我写其他文章的,可以在后台留言或者去知识星球【软件测试交流圈】提问喔,可以通过公众号菜单直达。毕竟,群里的消息一刷就过去了,有时候在忙,没能及时看到或者回复。
首先,在看这篇文章之前,希望大家先看一下上一篇文章,了解一下项目重构后,如何利用Postman快速对比出新旧接口之间的差异 。在上一篇文章中,基于这样的背景下,要快速对比两个接口的返回结果的差异 ,而且是大批量的接口,断言是很麻烦的,要对js非常熟练,因此,当时考虑想换一个扩展性强一点的工具,当时就考虑用RobotFramework框架。目前现有脚本都在postman中了,接下来要做的就是如何去快速的把postman中的接口测试用例都转成RF格式的用例呢? 几经辗转,最终github上找到了一个别人开源的脚本,clone下来试了一下,仓库地址如下:https://github.com/xNok/postman2robotframework 该仓库的脚本可以将postman导出的json格式的collections的文件转换为一个指定模板的.py的python脚本。并且提供了cli的命令行去进行转换,也提供了转换的demo,也可以将这个作为一个library安装到自己的python安装目录下的site-packages中去,安装命令是:代码根目录下执行: python setup.py install具体的用法,github上都有写:postman2robot 的命令要传2个参数,一个指定postman导出的json文件,另一个指定转换后的文件的目录。使用提供的demo文件转换后的效果如下: 相当于把postman的每个接口都定义成了一个python的函数,然后将python文件导入到RobotFramework框架中的话,每个函数相当于就是一个新的关键字。上面只是写到怎么样转换为RF的脚本,那么,怎么转换为pytest的用例脚本呢?其实只需要将/src/assets/library_template.py文件改一下格式。原来的内容如下: 要改成支持pytest的话 ,我们改一下class类名,然后在每个def函数名的前面或者后面加上test,再导入pytest的包,这样的话,就可以识别为pytest的用例了。然后在最后面再补充加一个if __name__ == '__main__'的脚本去执行pytest的用例,这样的话,就基本上完成了用例的转换工作。至于转换的模板文件中还需要加入什么可以自己去扩展。 然后再本地搭建好allure的环境之后,可以集成pytest一起运行后出一个漂亮的报告出来。下图是我转换之后的脚本,对比重构前与重构后的接口对比结果的报告:至于不知道怎么集成allure以及pytest的基本用法的,可以参考下面这篇文章:一篇文章为你揭秘pytest的基本用法脚本的运行和调试,需要有一定的python代码基础,我自己也在这个基础上调整了一些代码,如果你们对这个转换感兴趣,自己动手去尝试了之后遇到了问题的,可以添加好友一起探讨一下。
背景:最近接了一个项目,在现有的项目基础上,购买了一个新的数据源,需要将底层的数据进行更换,为了后续能够更好的扩展和维护,在替换的时候,会重新设计表结构要求:对外提供的接口要保持原样输出,接口入参格式和请求路径均与原来保持一致,尽可能的做到对下游无感知。设计到的接口改动比较多 ,大概有好几百个的样子吧。如果接口返回结构不一致,需要人工去确认是否对下游造成影响。(对应微服务均支持通过swagger去调用接口)由于具体改动设计公司业务,在这里不便细说,这里简单介绍下我是怎么去对比的,供大家参考学习。思路:由于接口数量比较多,如果自己写脚本去录入用例的话,效率估计也没这么快。swagger上面虽然支持单个接口直接调试调用,但毕竟不支持对比,而且也不好做批量执行,万一开发改了脚本之后,再回归的话,这么多接口要回归,时间上都是个问题。于是,决定采用postman工具去实现新旧接口的对比功能。具体实现步骤:1、将微服务下的所有接口导入postman中postman是支持导入swagger-ui的json文件的,但是可能存在版本的兼容性问题导致导入报解析错误,可以间接的借助apifox工具,先将swagger的数据导入apifox,再从apifox导出文件,然后再导入postman2、在postman的前置脚本Pre-request Script中写脚本先调用旧服务的接口发送请求,然后新接口直接在postman中发送请求Pre request Script中的脚本参考:var old_request = pm.request.clone(); const host = pm.environment.get("oldHost"); const port = pm.environment.get('oldPort'); old_request.update(old_request.url.host=host); old_request.update(old_request.url.port=port); pm.sendRequest(old_request,function (error, old_response){ if (error) { console.log(error); } else { if(old_response.responseSize==0) { pm.environment.set("old_response",{}); } else { console.log('old_response',old_response.json()) ; pm.environment.set("old_response", old_response.json()); } } });3、然后在Postman的Tests中加入断言脚本,对比新旧接口的返回结果是否一致。说明:由于重构过程中,可能部分接口没办法完全做到数据返回一致,再加上对js的用法不太熟练,这里可以采用Python脚本编写断言的脚本,思路就是:用python写一个后端服务,启动服务之后,对外提供几个断言的接口,然后在postman中写js发请求调用http请求去请求自己封装的python断言接口即可。Python服务封装接口如下:from flask import Flask, redirect, url_for, request import json import deepdiff app = Flask(__name__) @app.route('/assert_json', methods=['POST']) def assert_json(): if request.method == 'POST': # 默认返回内容 return_dict = {'status_code': '200', 'message': '处理成功', 'data': None} # 判断传入的json数据是否为空 if len(request.get_data()) == 0: return_dict['status_code'] = '500' return_dict['message'] = '请求参数为空' return json.dumps(return_dict, ensure_ascii=False) old_response = request.json.get("old_response") new_response = request.json.get("new_response") compare_result = deepdiff.DeepDiff(old_response, new_response, ignore_order=True) return_dict['data'] = compare_result print('compare_result', compare_result) # 对参数进行操作 return json.dumps(return_dict, ensure_ascii=False) @app.route('/assert_array', methods=['POST']) def assert_array(): if request.method == 'POST': # 默认返回内容 return_dict = {'status_code': '200', 'message': '暂不支持该格式断言,后续扩展', 'data': None} return json.dumps(return_dict, ensure_ascii=False) if __name__ == '__main__': app.run(debug=True)在python中对比接口的话 ,采用的是deepdiff,可以很轻松的对比出返回结果为json格式的两个json的差异。然后在Postman中的Tests脚本中调用自己的断言方法的脚本如下:var old_response = pm.environment.get("old_response"); //console.log('old_response',old_response) ; var new_response = pm.response; if(new_response.responseSize==0) { new_response = {} } else { new_response = new_response.json(); } console.log('new_response',new_response) ; url = '' // 判断返回结果是数组还是json,调用不同的方法去断言(转成字符串,判断是以[还是{开头) if (JSON.stringify(new_response).toString().startsWith('{')) { url = 'http://127.0.0.1:5000/assert_json' } else if(JSON.stringify(new_response).toString().startsWith('[')){ url = 'http://127.0.0.1:5000/assert_array' } const compareRequest = { url: url, method: "POST", header: 'Content-Type: application/json', body: { mode: 'raw', // 使用raw(原始)格式 raw: {"old_response": old_response, "new_response": new_response} //要将JSON对象转为文本发送 } }; // 发送请求 pm.sendRequest(compareRequest, function (err, res) { compare_result = res.json().data pm.environment.set("compare_result",compare_result); }); compare_result = pm.environment.get("compare_result") pm.test("对比两个接口返回结果", function () { console.log("对比result:",compare_result); pm.expect(compare_result).to.eql({}); });以上只是对比的大概思路,可以将这些脚本放置在Collections级别的Pre-requests Script和Tests中,做通用的断言。如果针对不同的接口有不同的断言的话,可以针对Collections下的接口再进行个性化的断言。按照以上的思路,可以在postman中扩展很多原本不支持的功能哟。
先来说一下背景,为什么要写脚本去读Consul的配置信息呢?Consul是啥呢?consul是google开源的一个使用go语言开发的服务发现、配置管理中心服务。目前公司用的是这个东西去管理项目上的一些配置信息。公司的环境是通过docker镜像的方式去部署的,镜像是通过rancher去进行管理的。这一套东西面临的一个问题是:服务每次更新之后,服务对应的ip地址是动态变化的。每次需要使用swagger去测接口的时候,都要去rancher上去重新找新的ip地址,比较麻烦。正好呢,最近部门在考虑准备做接口自动化测试,到时候ip总是变的问题也是需要解决的,因此,就先写个脚本调接口获取配置信息,拿到某个服务的ip和端口信息。顺带的把swagger地址也打印出来,以后要访问某个服务的swagger地址就方便很多了。python读取Consul配置信息的话,用到的是python-consul库,在使用前,需要先安装一下对应的插件。pip install python-consul封装好的读取consul配置的类如下:以下脚本中定义的函数,暂时只做数据打印,并未返回具体的数据,因为不同的consul地址,上面的配置信息其实还需要做处理,比如我这次主需要取出一些部署的服务的ip和端口信息,但是consul上面还有一些其他的配置信息,是可以过滤掉的。并且,有的配置项可能由于配置错误,会存在重复的配置,暂时没有删除,这种的话,后续可以在脚本中根据返回的相关字段,去取有效的配置信息。import consul class RFConsul(object): def __init__(self, host, port): """初始化,连接consul服务器""" self._client = consul.Consul(host, port, scheme='http', verify=False) def getAllServices(self): services = self._client.agent.services() for i in services: service = services.get(i) print({service['Service']: service}) def getServiceByName(self, service_name): data = self._client.catalog.service(service_name) for value in data[1]: print(service_name + "服务的swagger地址: " + "http://" + value['ServiceAddress'] + ":" + str(value['ServicePort']) + "/swagger-ui.html")getServiceByName:根据服务名,调用后,直接打印拼接好的swagger-ui的访问地址。getAllServices:打印某个consul地址下的所有配置信息。调用方式:host = "127.0.0.1" # consul服务器的ip port = "8500" # consul服务器对外的端口 consul_client = RFConsul(host, port) consul_client.getAllServices() res = consul_client.getServiceByName("xxx-servicename") # 输入配置项的名称调用后,直接得到类似下图的swagger访问地址是不是很香:然后,在公司中的话,像这种配置中心的地址一般都需要通过代理才能访问,公司用的是socket5的代理,一般在调用脚本的时候要把代理软件打开。也可以在脚本中添加socket代理的配置信息:import socket import socks socks.set_default_proxy(socks.SOCKS5, "ip", port) socket.socket = socks.socksocket能阅读到此文的一定是小博的铁粉,可以添加一下微信好友(xiaobotester),没事的时候互相交流学习哟。如果你是还没入门或者正准备入门软件测试行业的,或者从事数据测试相关的工作的,都可以找我来取取经喔。
3.10正式版发布Python近几年来越来越火了,而且版本也一直在不停的更新迭代中。Python在2021/10/04发布了3.10的正式版,虽然你可能还没有升级,不过也可以先大概了解一下在新的版本中做了哪些改动哟。官方的升级介绍(相比3.9版本):https://docs.python.org/3/whatsnew/3.10.html1、错误提示变得更加友好以前写脚本的时候,如果写了一行脚本,少写了一个括号啥的,错误提示不够直观,找错误还得找半天。下面看下python3.9版本中的错误提示:a = (1,2,3同样的脚本,再看下python3.10版本下的提示:what?是的,你没有看错,python会告诉你括号没有成对出现。那是不是所有的错误,都能够提醒的这么智能呢?当时不是,有可能是现在新版本才刚出来,对比比较复杂的写法支持的还不够好,下面这个例子提示的就不够直观:同样是少了一个括号,看来能识别的场景有限呀,期待后面能变得更加强大。2、加入了match case的用法match ... case 语法类似于其它语言中的 switch ... case 语法,在多条件判断时比用 if ... elif 代码更简洁。下面看下match case的用法:def http_error(status): match status: case 400: return 'Bad Requests' case 404: return 'Not Found' case _: return 'other error' print(http_error(400)) print(http_error(404)) print(http_error(500))输出结果:Bad RequestsNot Foundother errorcase _ 类似于其它语言中的 default ,当其他条件都不符合就执行这行。也可以在case语句后面使用 | 去进行连接:case 401 | 403 | 404: return "Not allowed"在以后封装测试脚本的时候,也可以用上这个功能喔:def send_requests_method(method): match method: case 'GET': return send_get_requests() case 'POST': return send_post_requests() case 'PUT': return send_put_requests() case _: pass3、新的类型联合操作符在以前的版本中,要针对一个函数的入参做多种类型支持的话,要用到Union:from typing import Union def square(number: Union[int, float]) -> Union[int, float]: return number ** 2现在有个新的语法糖“|”,叫联合操作符,可以让代码更简洁def square(number: int | float) -> int | float: return number ** 2该操作符在函数 isinstance()和 issubclass() 也可以支持print( isinstance(1, int | str)) print(issubclass(int, int | str))4、支持带括号的上下文管理器比如之前读取文件的操作是这样的:with open('file1', 'r') as f1, open('file2', 'r') as f2: print(f.read())在3.10版本中,可以用括号将多个上下文放在一起: with ( open('run.py', 'r') as f1, open('run.py', 'r') as f2 ): pass但是目前这种写法在pycharm中可以会有标红的错误提示,但不影响实际运行。
今天来介绍一下Python中的运算符,运算符主要有以下几类:算术运算符比较(关系)运算符逻辑运算符赋值运算符三目运算符位运算符成员运算符身份运算符接下来,详细的介绍一下运算符的具体操作:算术运算符算术运算符用于对整数类型和浮点类型的数据进行相关操作的运算符。常见的算术运算符以及对应的操作介绍如下图所见:如果将True/False用于数值的操作运算的时候,会自动转换为1和0去进行计算。比较运算符比较运算符主要用于比较两个表达式的大小,对比的返回结果是True或者False。False。运算符名称例子说明>大于a>ba大于b时返回True,否则False==等于a==ba与b相等时返回True,否则False<小于a<ba小于b时返回True,否则False>=大于等于a>=ba大于等于b时返回True,否则False<=小于等于a<=ba小于b时返回True,否则False!=不等于a!=ba与b不相等时返回True,否则False实例演示:下面考考你在python中,以下语句执行结果分别是什么呢? print(1.0 == 1) ==>True print(1 == True) ==>True print([2,1]>[1]) ==>True print(['1']>[1]]) ==>运行报错逻辑运算符逻辑运算符用于对布尔型变量进行运算,其结果也是布尔型。and 与(and两边的值都为True时,返回True)or 或 (or两边的值只要有一个为True时,返回True)not 非,(将true变为false,false变为true)请看具体案例:print(True and True) #True print(True and False) #False print(False and False) #False对于 a or b 来说,如果 a 为真,那么值为 a,否则为 b;对于 a and b 来说,如果 a 为真,那么值为 b,否则为 a。print(True or False) #True print(False or True) #True print(False or False) #Falseprint(not True) #False print(not False) #True 具体的运行效果如上面脚本所示,要注意的是,像这种逻辑运算符,在运行过程中,采用了类似“短路”的设计,and 和 or操作在运算的时候,如果结果已经确定,就不会再去计算后面的表达式。比如:True or False ,前面的True已经确定最终返回的结果会为True,就不会再去管or后面去True还是False。总之:and要所有数据都为True才返回True,or只有有一个为True则返回True。赋值运算符=是最常见的赋值运算符,比如a=3,就表示将3的值赋值给变量a。其他常见的赋值运算符有:+=、-+、*=、/=、%=、//=、**=等。a+=b ==> a=a+b a-=b ==> a=a-b a*=b ==> a=a*b三目运算符这个一般用在if判断条件中比较常见,比如,求2个数中的最大值,普通的写法如下:if a>b: max = a else: max = bpython中提供了一个简便的写法,代码看上去简洁很多:max = a if a>b else bpython中通过if else的条件判断,可以实现类似java里面的?:三目运算符。java里面的用法如下:z = x>y ? x-y : x+y;python里面用法:value1 if 判断条件 else value2 稍微复杂点的写法:a if a>b else c if c>d else d 等价于:a if a>b else ( c if c>d else d )成员运算符in :如果在指定的序列中找到值返回True,否则返回Falsenot in :制定的序号中没有找到对应的值则返回True,找到则返回False成员运算符用的还是比较多的,比如查看某个key是不是在某个字典里面时,可以用 key in dict.keys()去判断a = {"A": "1", "B": "2"} print('A' in a.keys()) print('a' in 'abcdefg')身份运算符is、is not,用来判断两个标识符是否引用的同一个对象a1 = 10 b1 = 2 b1 += 8 print(a1 is b1) #True s1 = 'abc' s2 = '123abc'[3:] print(s1 is s2) #False a1 = 1 print(a1 is True) #False
之前写了文章介绍python中的列表和字典,在文章中描述到了python中的列表是有序的,字典是无序的,后来有粉丝在群里提醒我,说python3.6的版本之后,字典是有序的,因此,我找了一个低版本的python来验证一下效果:首先,从官网下载python3.4的版本,然后编写一行代码验证一下打印字典的所有key。查看打印出来的key的顺序:Python3.6以下版本:(以3.4版本为例)你该不会以为只有使用keys()函数是无序的吧:从上图可以看出,分别在cmd窗口和pycharm中打印字典的key值,发现打印的顺序每次重新在一个新的窗口运行,打印的顺序都不一致。并且pycharm中会显示,python3.4的版本在pycharm中已经不再支持了。接下来再看下python3.6以上版本的效果:(以3.9版本为例)从上图可以看出,在新的版本中,python针对key的存储已经变为有序,在遍历和打印的时候,会按照存储的顺序进行取值。再补充一点:之前介绍到,在字典中,key是唯一的。这里并不是说写了不唯一的key就会报错,只是会用后面的key和value去覆盖前面的key和value。a = {'a': 1, 'b': 2, 'b': 3} # 在运行的时候不会报错PS:最近小编联合其他测试大佬正在整理python从零开始学自动化以及测试开发的一系列文章,大家都在群里互相学习讨论,每天输出学习的笔记文章,感兴趣的小伙伴可以扫码加入,一起互相学习喔。
在之前的文章中,已经介绍过,如何去设计测试用例,并且以一个开源电商项目的后台某个模块去分析了一些比较常见的测试点,那么,今天将针对这个模块进行功能测试,看一下在测试过程中,我们能发现一些什么样的问题呢?接下来按照功能点的方式,列举部分我发现的问题,供大家参考,希望对正在自学软件测试或者参加培训后对项目实战还一脸懵逼的朋友们能有所帮助吧。一、搜索相关的功能验证1、点击搜索按钮的时候,页面体验性不好,整个页面不应该变空白然后再加载出数据,应该只刷新下面列表的数据就OK2、展开更多筛选条件后,点击清除条件按钮后,整个页面不应该刷新3、按照邮箱搜索不到数据4、搜索条件的时间字段应该标注明确是具体根据哪个时间搜索,比如改成注册时间5、按日期搜索功能有bug,选择2021-08-12~2021-08-12 查询不到注册日期为2021-08-12的数据6、搜索功能有问题,输入特殊字符%可以查到所有数据(这里应该是有sql注入的安全漏洞)7、页面没有明显标识一页显示多少数据8、页面不应该出现页面层级的上下滚动条,滚动条应该位于数据表格中,建议查询条件应该是固定展示在顶部二、导出功能验证1、导出数据时,没有按照页面搜索条件导出数据2、列表数据为空时,应该提示用户无数据,不导出空文件3、导出的文件名可以改成用户列表+时间,这种属于优化建议,可改可不改三、新增、编辑、查看功能验证1、没有做必填字段校验,不完整的数据不应该让入库,比如像用户名/手机/邮箱,这个是登录账号,不能为空2、没有做数据唯一性校验,比如像用户名/手机/邮箱,这个是登录账号,肯定不能重复3、生日设置今天之后的日期居然也没有提示4、积分设置一个负数保存时会报错:SQLSTATE[22003]: Numeric value out of range: 1264 Out of range value for column 'integral' at row 15、密码输入框应该采用密码控件,输入密码是应该显示..........6、新增用户时,密码应该设置为必填,或者页面有友好提示,默认密码是多少,不然新增的用户无法登陆,新增的是垃圾数据7、查看功能显示地址有省份字段,但是后台没有地方维护,只能维护地址详细信息。四、扩展测试场景还有部分其他场景,我这里没有一一去进行测试,也算是对之前写测试点的一些补充,大家感兴趣的可以自己去模拟一下。1、将用户的账户改为禁止登录、禁止发言等状态,分别验证对应的功能是否正常2、检查一下后台操作是否有做权限控制,分别给自己分配觉得,去验证是否有对应的权限去操作。比如数据的删除什么的是比较敏感的,是否有做权限控制3、数据的修改是否有其他地方做了操作日志记录。到此,已经完成了一个电商模块的后台用户管理的用例设计与功能测试实战,不知道你们对软件测试的工作是否有了进一步的了解。在平常的用例设计工作,包括测试的时候,有很多的细节是需求文档里面不会给出来的场景,需要自己根据自己的测试经验去分析,这也是为什么有的人做功能测试,薪资待遇也还算可观的原因。大家如果需要看其他模块的测试点,或者学习过程中遇到其他问题的话,可以添加好友私信问我。
简单介绍一下使用pycharm的一些常规操作吧,工具安装之类的就不介绍了。只记录自己偶尔会用到的一些功能。Pycharm支持python的多个版本,可以自由切换python版本执行脚本。下载地址:从官网下载 https://www.jetbrains.com/pycharm日常使用下载社区版本就行,激活码就不在这里提供了,有需要的话私聊我,发给你们,网站都可以找到的激活码的,过期了重新获取一下就行Tips:1、使用pytharm编写脚本时,记得在.gitignore文件中添加 一行:.idea/ ,添加后,这个目录下的文件将不会上传到git仓库上,避免其他电脑下载你的功能还需要重新配置。如果git仓库中已经上传了.idea文件夹,需要删除后再添加.gitignore文件,不然不会生效2、常用快捷键:Shift + F6: 文件重命名Ctrl + F12: 显示当前文件结构,当文件方法过多时,可以快速选择Ctrl+Alt+S:打开设置页面Ctrl+/:注释快捷键有很多,剩下的可以自己去了解3、Pycharm设置去除显示的波浪线方法一:打开pycharm在右下方有一个医生头像的小图标,点击打开,如下图:但是该方法只针对本文件生效其他文件还是会有相同的问题方法二:1、顶部菜单 file->settings (快捷键 Ctrl+Alt+S)2、选择Editor—Color Scheme—General选项,然后选择右边对话框中的Errors and Warnings选项,选择选项下方的weak Waring,然后将界面右边的Effects去掉勾选即可。如下图:4、设置文件模板 ,设置之后,每次新建py文件的时候,会有一个默认模板,大家可以根据自己的喜好进行调整,这里我用的是这个模板:# -*- coding: utf-8 -*- # Time:${DATE} ${TIME} # Author : 小博 # Description : # WX :xiaobotester大家也可以按照上面的操作新建其他格式文件的模板喔,比如html,xml这些都可以设置模板的。5、设置python默认路径在pycharm中创建项目的时候,新手很容易创建虚拟环境,然后采用虚拟环境下的python去运行脚本。虽然说虚拟环境有隔离的效果,可以不受其他环境的干扰,但是对于初学者,有时候用命令行安装一些插件的时候,会遇到明明已经安装过插件了,但是运行脚本还提示找不到某某某插件的错误,这个时候可能就是插件安装所使用的的python环境和pycharm工具中使用的环境不一致导致的。这里建议电脑环境变量中的python路径和pycharm工具中都使用统一的路径。pycharm中的路径设置方法如下:
在之前的文章中,已经教大家搭建了电商网站,如果有没找到的,可以再私聊一下我。接下来,简单介绍一下,在公司中,一般我们怎么去开展测试。 这里我们抛开所有的理想状态,就只有这个项目的访问地址,数据库信息,没有需求文档,我们要怎么样去写测试用例,怎么样去进行测试。当你具备在这样的条件下也能够胜任软件测试工作,那么,当你自学或者是培训软件测试入行的时候,你还会担心找不到工作,或者入职之后没办法胜任工作吗?项目前端访问地址:http://8.129.162.225:8080/后台管理地址:http://8.129.162.225:8080/admin.php需求分析:俗话说得好,没吃过猪肉还没见过猪跑吗?就算没有需求文档,淘宝网站平常总用过吧,如果之前再有过开淘宝店铺经验的话,就更好理解后台的业务。前端是给用户购买所展示的页面,页面上的数据是前端通过调接口返回的,接口返回的数据是从数据库中查询的,数据库中的数据是在后台管理有一个系统专门去维护这些数据。因此,我们在设计测试用例,考虑测试点的时候,就应该要考虑到前端和后台管理系统之间的业务联系。接下来,先挑选后台的用户列表模块,进行用例设计。页面如下图所示:在工作中,怎么开始设计用例呢?一般都会先用思维导图的方式先提取一些比较粗的测试点,然后再根据脑图细化成单条的用例录入到用例管理平台/excel中。这里简单的列举了一些比较粗的测试点: 以下的测试点是在没有需求文档的前提下,自己列举的一些简单的测试点,至于具体怎么样去完善成最终在excel里面的用例,在这里希望刚入门的朋友,自己根据之前的文章学习一下用例设计,然后去用这个模块实战一下。然后有需要的话,可以私聊我帮你看一下用例写的怎么样,标题什么的是否需要优化。想看这个系统其他模块测试点整理的,也可以私聊或者评论下。
本文介绍通过linux系统下的小皮面板进行安装。下载安装脚本:https://www.xp.cn/linux.html打开上面的网址,然后打开我这里选择的是无docker版本的。因为我在自己的阿里云服务器上安装过docker,用他的软件再安装的时候,会提示我安装或docker,建议在一个干净的环境中去进行安装。Centos系统安装命令:yum install -y wget && wget -O install.sh https://notdocker.xp.cn/install.sh && sh install.sh执行完上面的命令之后,会出现下面的提示:出现以上截图内容后,浏览器输入外网访问地址即可访问小皮面板:在软件管理里面安装mysql、php等其他环境:这里建议mysql使用mysql5.7.27,php默认有一个版本,建议装一个5.6或者更新的版本,因为其他项目使用的时候,太低的版本会出现兼容性问题。接下来,部署一个网站用来练习:在软件管理下点击网站程序,然后找到shopxo项目:点击一键部署后,弹窗页面如下:安装完后,在左侧菜单网站那里,可以找到该项目,可以通过配置按钮更改端口。默认是80端口,我这里更改为了8080端口注意:在阿里云/腾讯云服务器上操作的话,要在安全组开放相关端口才能访问。安装完之后,前端访问网址:http://8.129.162.225:8080/后端管理系统网址:http://8.129.162.225:8080/admin.php 账号密码可在安装网站的页面可以看到:页面访问效果如下:商城首页:商城后台:在小皮面板的【服务器防火墙】菜单下,放开数据库3306端口,让外部可以访问。(小皮面板和阿里云的安全组里面都要放开端口)放开后,可以用GUI工具连接数据库:如果还有连接不上的,可以在左侧菜单【数据库】下面开启root用户远程连接权限:然后,设置数据库的权限为所有人可访问:至此,整个项目的前端、后台管理、以及数据库都可以访问,接下来就可以开启你们的转行/入行自学之路啦。可以利用该网站编写测试用例、找bug、练习数据库基本语法的使用、抓包工具的使用、自动化测试、性能测试等测试所需的技能。没有linux服务器或者虚拟机的,可以在windows机器上搭建,操作步骤类似。建议:1、刚开始接触这个的时候,不要花太多的时间在环境搭建上,选择那些一键安装的快捷方式就行,不要去折腾什么源码安装之类的,这并不能证明你的能力,相反,还可以出现各种未知的问题,耽误学习的时间。2、在学习过程中,难免会遇到问题,就算照着别人的文档教程操作,也不能保证一定不出现问题,但是,出现问题后不要气馁,自己花长时间还解决不了的问题,要么就停下来换个思路,要么就寻求帮助。如果需要该项目访问的相关账号信息等,可以添加微信获取。
不知道大家有没有遇到过这个错误:ModuleNotFoundError: No module named xxx .相信对于大部分python的初学者来说,这个错误并不陌生,就是没有安装插件导致代码运行的时候报错。那么,有没有在明明已经安装成功的情况下,环境变量也配置成功了,还是遇到过这个错误呢?比如,在pycharm里面可以运行,并且pycharm里面没有使用虚拟环境,直接使用的系统安装路径下的python。但是在cmd窗口中执行命令运行脚本的时候,却奇怪的报错。这个时候可以按照以下思路去排查一下:1、如果看到有人截图说报ModuleNotFoundError: No module named 'xxx'的错误的,先看看是不是在pycharm等编辑器中使用,可以先看一下是否使用了python的虚拟环境,然后相关的依赖包没有在虚拟环境中进行安装。2、检查是不是import module的时候名字写错了3、在排查了以上情况后,可以试试检查一下python环境变量的配置,在cmd窗口中输入python,看看环境变量配置是否有问题4、在cmd窗口输入pip list,然后看看是否与预期显示的插件列表一致,这一步一般能发现问题。当不一致的时候,可以执行where pip 命令查看pip使用的是哪个目录下的 。我这里遇到的情况是: 之前可能装过多个版本的python,并且来回切换/卸载过版本,导致用户目录下的\AppData\Local\Microsoft\WindowsApps目录下存在pip,python等exe文件,在cmd窗口中执行的时候,没有使用正确路径下的程序去执行,可以将这个目录下的文件进行删除即可恢复正常。这个目录下的文件直接删除可能会删除失败,可以考虑使用360安全卫士里面的文件粉碎功能就可以正常删除。
通过前面几个章节的文章,我们学会了通过PySide2去编写一个简单的GUI页面测试小工具:Python GUI编程:PySide2介绍Python GUI编程:如何运行第一个PySide2的窗体程序Python GUI编程:PySide2页面设计优化Python GUI编程:PySide2通过加载页面设计文件的方式运行Python GUI编程:通过PySide2实现一个简单的postman工具接下来,看一下怎么样将编写好的脚本,打包成一个双击可以运行的exe文件:这里需要用到python的一个插件pyinstaller。可以先检查一下自己电脑有没有安装这个插件:pip show pyinstaller如果没有安装的话,可以使用下面的命令进行安装:pip install pyinstaller表 1 PyInstaller 支持的常用选项-h,--help查看该模块的帮助信息-F,-onefile产生单个的可执行文件-D,--onedir产生一个目录(包含多个文件)作为可执行程序-a,--ascii不包含 Unicode 字符集支持-d,--debug产生 debug 版本的可执行文件-w,--windowed,--noconsolc指定程序运行时不显示命令行窗口(仅对 Windows 有效)-c,--nowindowed,--console指定使用命令行窗口运行程序(仅对 Windows 有效)-o DIR,--out=DIR指定 spec 文件的生成目录。如果没有指定,则默认使用当前目录来生成 spec 文件-p DIR,--path=DIR设置 Python 导入模块的路径(和设置 PYTHONPATH 环境变量的作用相似)。也可使用路径分隔符(Windows 使用分号,Linux 使用冒号)来分隔多个路径 --distpath DIR指定exe文件生成的目录,默认是./dist ,及当前目录下的dist文件夹-n NAME,--name=NAME指定项目(产生的 spec)名字。如果省略该选项,那么第一个脚本的主文件名将作为 spec 的名字在表 1 中列出的只是 PyInstaller 模块所支持的常用选项,如果需要了解 PyInstaller 选项的详细信息,则可通过 pyinstaller -h 来查看。可以使用下面的命令进行打包:pyinstaller -F -w --distpath . rungui.py执行上面的命令后,即可打包成exe文件,正常情况下双击即可运行。可能会遇到的问题:1、由于代码中加载.ui的页面设计文件用的相对路径,导致打包的时候,没有将ui文件一起打包进去,此时双击exe就会报错:解决办法:将ui文件、图标文件等和exe文件放在同一个目录后,再双击执行,就不会有这个问题。感兴趣的,也可以尝试将ui文件放到python安装目录的某个位置,然后代码中读取文件的位置改一下 ,估计不会报错。控件的其他学习资料,可以参考以下网址:http://www.byhy.net/tut/py/gui/qt_01/感兴趣的,可以再研究一下,在postman工具中调用百度网址发送请求的时候,如何优化响应结果显示,以及当返回结果很大,或者响应很慢时,如果避免exe程序直接卡死的情况:
前置文章:Python GUI编程:PySide2介绍Python GUI编程:如何运行第一个PySide2的窗体程序Python GUI编程:PySide2页面设计优化Python GUI编程:PySide2通过加载页面设计文件的方式运行在掌握了以上4篇文章的内容后,我们可以画出一个简易的postman工具的页面,如下图所示:接下来,我们就实现send按钮发送请求的功能:要实现这个功能,主要需要了解以下几点:1、下拉框如何获取选中的值获取ComboBox索引和选中的文本值,索引从0开始 ComboBox.currentIndex(), ComboBox.currentText()2、文本框如果获取选中的值QLineEdit.text()3、按钮怎么绑定事件QPushButton.clicked.connect(方法名)4、怎么将某个文本显示到某个控件上控件名.append("文本")完整的代码如下:import sys, requests from PySide2.QtCore import QFile from PySide2.QtUiTools import QUiLoader from PySide2.QtWidgets import QApplication # 1、创建一个应用程序 app = QApplication(sys.argv) # 2、打开.ui文件 qFile = QFile('postman.ui') qFile.open(QFile.ReadOnly) # 只读方式 # 3、加载文件,生成一个页面对象 ui = QUiLoader().load(qFile) qFile.close() # 做一些逻辑处理 def click_send_btn(): method =ui.method_comboBox.currentText().lower() url = ui.url_text.text() res = requests.request(method=method, url=url).text ui.res_textEdit.append(res) print(method, url) def click_exit_btn(): ui.close() ui.send_btn.clicked.connect(click_send_btn) ui.close_btn.clicked.connect(click_exit_btn) # 4、显示应用程序 ui.show() app.exec_()页面UI设计文件源码如下:<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>PostmanTools</class> <widget class="QDialog" name="PostmanTools"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>948</width> <height>537</height> </rect> </property> <property name="windowTitle"> <string>简易Postman Tools</string> </property> <widget class="QComboBox" name="method_comboBox"> <property name="geometry"> <rect> <x>70</x> <y>30</y> <width>81</width> <height>31</height> </rect> </property> <item> <property name="text"> <string>GET</string> </property> </item> <item> <property name="text"> <string>POST</string> </property> </item> </widget> <widget class="QLineEdit" name="url_text"> <property name="geometry"> <rect> <x>170</x> <y>30</y> <width>541</width> <height>31</height> </rect> </property> </widget> <widget class="QPushButton" name="send_btn"> <property name="geometry"> <rect> <x>760</x> <y>30</y> <width>151</width> <height>31</height> </rect> </property> <property name="text"> <string>Send</string> </property> </widget> <widget class="QLabel" name="label"> <property name="geometry"> <rect> <x>70</x> <y>90</y> <width>72</width> <height>15</height> </rect> </property> <property name="text"> <string>Params</string> </property> </widget> <widget class="QLabel" name="label_2"> <property name="geometry"> <rect> <x>160</x> <y>90</y> <width>121</width> <height>21</height> </rect> </property> <property name="text"> <string>Headers</string> </property> </widget> <widget class="QTextEdit" name="res_textEdit"> <property name="geometry"> <rect> <x>70</x> <y>150</y> <width>821</width> <height>331</height> </rect> </property> </widget> <widget class="QPushButton" name="close_btn"> <property name="geometry"> <rect> <x>280</x> <y>90</y> <width>93</width> <height>28</height> </rect> </property> <property name="text"> <string>Close</string> </property> </widget> <widget class="QPushButton" name="reset_btn"> <property name="geometry"> <rect> <x>420</x> <y>90</y> <width>93</width> <height>28</height> </rect> </property> <property name="text"> <string>重置</string> </property> </widget> </widget> <resources/> <connections/> </ui>运行效果:接下来就可以自己扩展一下页面设计,然后实现更多的功能。另外,如果响应结果太大,页面渲染会卡死,也可以思考一下如何去优化。
章节回顾:Python GUI编程:PySide2介绍Python GUI编程:如何运行第一个PySide2的窗体程序总结:通过以上2篇文章,可以收获在python语言中,实现GUI编程,开发自己的一些测试小工具,但是还有很多地方可以优化,比如:之前讲的窗体运行需要先将ui文件转换为python脚本,再编写代码去启动,每当页面重新设计的时候,需要重新转换代码,并且每次转换会覆盖之前自动生成的脚本。带着以上的问题,接下来看下如何优化:通过加载.ui文件的方式运行,直接上代码:import sys from PySide2.QtCore import QFile from PySide2.QtUiTools import QUiLoader from PySide2.QtWidgets import QApplication # 1、创建一个应用程序 app = QApplication(sys.argv) # 2、打开.ui文件 qFile = QFile('postman.ui') qFile.open(QFile.ReadOnly) # 只读方式 # 3、加载文件,生成一个页面对象 ui = QUiLoader().load(qFile) qFile.close() # 4、显示应用程序 ui.show() app.exec_()
前置条件:Python GUI编程:PySide2介绍Python GUI编程:如何运行第一个PySide2的窗体程序通过之前的文章,我们发现:在拖拽控件的时候,页面每一个控件的名称没有跳转,都是用的默认的,这样不方便后期去按钮,输入框等进行其他相关操作,会导致代码可读性差,接下来可以进行优化:1、针对拖拽生成的控件修改名称以下图为例,在Qt Designer软件中,点击对应的控件,可以看到控件的命名:下拉框默认是comboBox,页面有多个同类控件的话,默认会加下标区分。这里可以将控件命名改一下,方便后续使用。比如,上面的控件表示请求方式,就可以改为method_comboBox,修改之后的ui文件的文本内容如下:<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>PostmanTools</class> <widget class="QDialog" name="PostmanTools"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>948</width> <height>617</height> </rect> </property> <property name="windowTitle"> <string>简易Postman Tools</string> </property> <widget class="QComboBox" name="method_comboBox"> <property name="geometry"> <rect> <x>70</x> <y>30</y> <width>81</width> <height>31</height> </rect> </property> <item> <property name="text"> <string>GET</string> </property> </item> <item> <property name="text"> <string>POST</string> </property> </item> </widget> <widget class="QLineEdit" name="url_text"> <property name="geometry"> <rect> <x>170</x> <y>30</y> <width>541</width> <height>31</height> </rect> </property> </widget> <widget class="QPushButton" name="send_btn"> <property name="geometry"> <rect> <x>760</x> <y>30</y> <width>151</width> <height>31</height> </rect> </property> <property name="text"> <string>Send</string> </property> </widget> <widget class="QLabel" name="label"> <property name="geometry"> <rect> <x>70</x> <y>90</y> <width>72</width> <height>15</height> </rect> </property> <property name="text"> <string>Params</string> </property> </widget> <widget class="QLabel" name="label_2"> <property name="geometry"> <rect> <x>160</x> <y>90</y> <width>121</width> <height>21</height> </rect> </property> <property name="text"> <string>Headers</string> </property> </widget> <widget class="QTextEdit" name="res_textEdit"> <property name="geometry"> <rect> <x>70</x> <y>150</y> <width>821</width> <height>331</height> </rect> </property> </widget> <widget class="QPushButton" name="exit_btn"> <property name="geometry"> <rect> <x>280</x> <y>90</y> <width>93</width> <height>28</height> </rect> </property> <property name="text"> <string>Exit</string> </property> </widget> <widget class="QPushButton" name="reset_btn"> <property name="geometry"> <rect> <x>420</x> <y>90</y> <width>93</width> <height>28</height> </rect> </property> <property name="text"> <string>重置</string> </property> </widget> </widget> <resources/> <connections/> </ui>2、可以直接在GUI设计页面对按钮做一些简单的事件处理:
上一章节介绍了PySide2的安装以及如何去启动程序进行页面设计,并且将工具集成到pycharm的扩展工具中去,有2个地方写的不对,用的是pyuic工具,需要改一下,改成pyside2-uic.exe。具体改动点:pycharm扩展工具中的配置也需要调整一下:上一篇的配置写的是pyqt5的配置,这里主要采用PySide2进行学习。修改为正确的配置后,鼠标选中ui文件,右键选择扩展工具中的pyside2-uic就可以转换为python脚本。先看一下我画的一个简单的GUI页面:保存页面文件后,后缀是.ui的格式,用文本文件打开的话,内容是xml格式的:postman.ui源码:<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>Dialog</class> <widget class="QDialog" name="Dialog"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>948</width> <height>617</height> </rect> </property> <property name="windowTitle"> <string>Dialog</string> </property> <widget class="QComboBox" name="comboBox"> <property name="geometry"> <rect> <x>70</x> <y>30</y> <width>81</width> <height>31</height> </rect> </property> <item> <property name="text"> <string>GET</string> </property> </item> <item> <property name="text"> <string>POST</string> </property> </item> </widget> <widget class="QLineEdit" name="lineEdit"> <property name="geometry"> <rect> <x>170</x> <y>30</y> <width>541</width> <height>31</height> </rect> </property> </widget> <widget class="QPushButton" name="pushButton"> <property name="geometry"> <rect> <x>740</x> <y>30</y> <width>151</width> <height>31</height> </rect> </property> <property name="text"> <string>Send</string> </property> </widget> <widget class="QLabel" name="label"> <property name="geometry"> <rect> <x>70</x> <y>90</y> <width>72</width> <height>15</height> </rect> </property> <property name="text"> <string>Params</string> </property> </widget> <widget class="QLabel" name="label_2"> <property name="geometry"> <rect> <x>160</x> <y>90</y> <width>121</width> <height>21</height> </rect> </property> <property name="text"> <string>Headers</string> </property> </widget> <widget class="QTextEdit" name="textEdit"> <property name="geometry"> <rect> <x>70</x> <y>150</y> <width>821</width> <height>331</height> </rect> </property> </widget> </widget> <resources/> <connections/> </ui>转换之后的python脚本:postman.py# -*- coding: utf-8 -*- ################################################################################ ## Form generated from reading UI file 'postman.ui' ## ## Created by: Qt User Interface Compiler version 5.15.2 ## ## WARNING! All changes made in this file will be lost when recompiling UI file! ################################################################################ from PySide2.QtCore import * from PySide2.QtGui import * from PySide2.QtWidgets import * class Ui_Dialog(object): def setupUi(self, Dialog): if not Dialog.objectName(): Dialog.setObjectName(u"Dialog") Dialog.resize(948, 617) self.comboBox = QComboBox(Dialog) self.comboBox.addItem("") self.comboBox.addItem("") self.comboBox.setObjectName(u"comboBox") self.comboBox.setGeometry(QRect(70, 30, 81, 31)) self.lineEdit = QLineEdit(Dialog) self.lineEdit.setObjectName(u"lineEdit") self.lineEdit.setGeometry(QRect(170, 30, 541, 31)) self.pushButton = QPushButton(Dialog) self.pushButton.setObjectName(u"pushButton") self.pushButton.setGeometry(QRect(740, 30, 151, 31)) self.label = QLabel(Dialog) self.label.setObjectName(u"label") self.label.setGeometry(QRect(70, 90, 72, 15)) self.label_2 = QLabel(Dialog) self.label_2.setObjectName(u"label_2") self.label_2.setGeometry(QRect(160, 90, 121, 21)) self.textEdit = QTextEdit(Dialog) self.textEdit.setObjectName(u"textEdit") self.textEdit.setGeometry(QRect(70, 150, 821, 331)) self.retranslateUi(Dialog) QMetaObject.connectSlotsByName(Dialog) # setupUi def retranslateUi(self, Dialog): Dialog.setWindowTitle(QCoreApplication.translate("Dialog", u"Dialog", None)) self.comboBox.setItemText(0, QCoreApplication.translate("Dialog", u"GET", None)) self.comboBox.setItemText(1, QCoreApplication.translate("Dialog", u"POST", None)) self.pushButton.setText(QCoreApplication.translate("Dialog", u"Send", None)) self.label.setText(QCoreApplication.translate("Dialog", u"Params", None)) self.label_2.setText(QCoreApplication.translate("Dialog", u"Headers", None)) # retranslateUi单单有以上两个脚本是无法运行的,还需要单独再写几行代码来加载页面窗口进行展示:run_postman.py:import sys from PySide2.QtWidgets import QApplication, QMainWindow from postman import Ui_Dialog if __name__ == "__main__": # 创建一个Application对象 app = QApplication(sys.argv) # 创建一个窗体对象 MainWindow = QMainWindow() ui = Ui_Dialog() ui.setupUi(MainWindow) # 设置窗口显示 MainWindow.show() sys.exit(app.exec_())运行后的效果如下图所示:大家感兴趣的话,可以根据自己的喜好去调整页面设计,实现自己的测试小工具。
以前学java的时候,接触过用Swing编写GUI程序,在入职第一份工作的时候,公司的入职培训还教了我用WPF编写GUI客户端,今天,学习到了一个新的方式:那就是使用Python中的相关库进行编写GUI程序。在python中,支持图形化界面开发的库有很多,今天主要介绍一下PySide2这个库。这个的话,要结合PyQt一起对比理解,两者协议不同,也决定他们的使用场景不同。PyQt是GPLv3协议,如果你的程序中用了它,你的程序就要开源,如果闭源商用就会违反协议(后果自负,脸皮够厚无所谓)。PySide是LGPL协议,如果你只是作为库用它,你的程序还是可以闭源商用。安装插件:pip install -U PySide2 -i http://mirrors.aliyun.com/pypi/simple安装后,在python的安装目录下的插件目录那里,进入到%PYTHON_HOME%\Lib\site-packages\PySide2目录下后,会有一个designer.exe的文件,双击打开后,就可以图形化页面的设计工具,可以进行页面拖拽设计:工具打开后的页面如下:工具的拖拽页面,跟其他语言的图形化编程的插件差不多,左侧是一些控件的选项,需要什么可以直接拖拽到右侧的面板中。每次要到插件安装目录打开是不是很不方便呢?这里可以使用pycharm的扩展插件的功能,将该工具添加到扩展插件里面去。具体步骤如下:打开pycharm的setting页面,按下图进行配置:配置完之后,在pycharm的某个工程目录下鼠标右键,选择External Tools下面的工具就可以启动插件:图形化页面的设计文件是以.ui结尾的文件,可以通过pyqt5中的pyuic.exe的工具转换为python脚本。安装命令:pip install -U pyqt5 -i http://mirrors.aliyun.com/pypi/simple安装完只有,在python安装目录的Srripts的目录下,有一个pyuic5.exe的文件,可以使用如下命名将.ui的文件转换为python脚本:cd /d ui文件目录 pyuic5 xxx.ui -o xxx.py当然,也可以将pyuic5工具添加到pycharm的扩展工具里面去,具体配置如下:附上配置的文本信息方便大家复制:D:\Software\Python\Python39\Scripts\pyside2-uic.exe $FileName$ -o $FileNameWithoutExtension$.py $FileDir$Pycharm中pyuic5的插件使用:选择xxx.ui的文件,右键,然后选择External Tools下面配置的PyUic5即可在同层级目录下生成一个文件名相同,后缀名不同的python脚本。脚本内容如下图所示:(此时的python脚本直接运行是无法打开GUI页面的,需要再加入一些代码才能启动,具体如何运行,请期待后面的文章)
上一章节,我们采用多线程的技术去进行服务器端口的扫描,遗留了一些问题待优化,今天,我们采用协程的方式去尝试一下是否解决这个问题。 协程是一种轻量级的线程,协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态。也就是说同一线程下的一段代码执行着执行着就可以中断,然后跳去执行另一段代码,当再次回来执行代码块的时候,接着从之前中断的地方开始执行。 协程的优点:1、执行效率高,尤其是在线程数较多的情况下,与多线程对比的优势更明显2、不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好,因为执行效率比多线程高很多。缺点:1、无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。2、进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序接下来,让我们通过一段代码来看一下运行的效果:import gevent from gevent import monkey import time def fun1(): for num in range(3): print('fun1方法正在运行') #time.sleep(1) def fun2(): for num in range(3): print('fun2方法正在运行') #time.sleep(1) # 创建协程对象 t1 = gevent.spawn(fun1) t2 = gevent.spawn(fun2) monkey.patch_all() gevent.joinall([t1, t2])以上代码执行的时候,输出结果如下:fun1方法正在运行 fun1方法正在运行 fun2方法正在运行 fun2方法正在运行 fun2方法正在运行是不是跟预想的不一样呢,是的,因为程序执行没有阻塞/中断,所以打印结果没有交叉打印 ,把time.sleep(1)放开后,再执行:import gevent from gevent import monkey import time def fun1(): for num in range(3): print('fun1方法正在运行') time.sleep(1) # 协程遇到耗时操作后会自动切换其他协程运行 def fun2(): for num in range(3): print('fun2方法正在运行') time.sleep(1) # 协程遇到耗时操作后会自动切换其他协程运行 # 创建协程对象 t1 = gevent.spawn(fun1) t2 = gevent.spawn(fun2) monkey.patch_all() gevent.joinall([t1, t2])打印结果如下:fun1方法正在运行 fun2方法正在运行 fun1方法正在运行 fun2方法正在运行 fun1方法正在运行 fun2方法正在运行代码说明:本次采用gevent库实现协程的相关操作,在使用之前需要先安装该插件。安装命令:pip install geventgevent.spawn()函数:创建协程对象gevnet.joinall([传入携程对象列表]):会等待所有协程对象运行结束后再退出接下来改造端口扫描的代码,采用协程的方式实现:import socket import time import gevent from gevent import monkey from gevent.pool import Pool monkey.patch_all() def scan_port(host, port): sk = socket.socket() sk.settimeout(0.5) conn_result = sk.connect_ex((host, port)) if conn_result == 0: print(f'服务器{host}的{port}端口已开放') sk.close() def gevent_scan_host(host): # 8.129.162.225 start_time = time.time() run_list = [] g = Pool(200) # 限制协程并发数量,单线程的,不要设置太大 for port in range(0, 65536): run_list.append(g.spawn(scan_port, host, port)) gevent.joinall(run_list) end_time = time.time() print(f'耗时:{end_time-start_time}') host = input('请输入服务器ip地址:') gevent_scan_host(host)相关文章都是边学习边整理的笔记,如有错误,欢迎指正。如需进学习交流群,或者互相交流,文章催更,商务合作等,可添加微信xiaobotester ,记得备注一下。
前置条件:用Python代码编写一个简单的nmap扫描工具Python中多线程的基本操作前面学过了python中多线程的使用,也学了通过socket模块,去扫描服务器某个端口是否有开放。服务器的端口范围为0~65535,如果要针对所有的端口都进行扫描的话,耗时较长。假设每一个端口扫描的超时时长设置为0.5s,那么扫描完所有端口需要的时间为:65535*0.5≈9h 。因此,扫描的脚本需要进行优化,可以考虑使用多线程的方式去执行。优化前的脚本:def scan_port(host,port): sk = socket.socket() sk.settimeout(0.5) conn_result = sk.connect_ex((host, port)) if conn_result == 0: print(f'服务器{host}的{port}端口已开放') sk.close()加入多线程之后的脚本:import socket import threading import time def scan_port(host,port): sk = socket.socket() sk.settimeout(0.5) conn_result = sk.connect_ex((host, port)) if conn_result == 0: print(f'服务器{host}的{port}端口已开放') sk.close() # 8.129.162.225 start_time = time.time() host = input('请输入服务器ip地址:') thread_list = [] for port in range(0, 65536): t = threading.Thread(target=scan_port, args=(host, port)) thread_list.append(t) for thread in thread_list: thread.start() for thread in thread_list: thread.join() end_time = time.time() print(f'耗时:{end_time-start_time}')脚本优化效果:1、扫描本地开放端口,大概十多秒可以完成脚本存在的问题:1、脚本中批量一次创建65536个线程,部分电脑不一定能扛得住2、扫描出的结果不准确,尤其是在扫描远程服务器的时候,效果更明显,更容易看出问题学习交流或者文章催更,可加微信xiaobotester,添加的时候注明来意。
进程是资源分配的基本单位。线程是程序执行的最小单位。接下来以一段python脚本来演示一下多线程是如何去进行编码操作的,学会这个之后,就可以改进之前的脚本,将nmap的端口扫描工具改成多线程执行,提升效率。并且,在以后执行用例的时候,说不定也会需要用到这个技术。Python中多线程编程的代码演示:import threading import time def say_hello(msg): print(f'hello,我是:{msg}') time.sleep(2) start_time = time.time() # 1、创建线程 ''' target: 传可调用对象名字,一般是需要执行的函数名,默认为None args: 元组类型的参数,一般为target对象里面调用时的传参,默认为() ''' t1 = threading.Thread(target=say_hello, args=('a',)) t2 = threading.Thread(target=say_hello, args=('b',)) # 2、启动线程 t1.start() t2.start() # 3、join所完成的工作就是线程同步,即主线程任务结束之后,进入阻塞状态,一直等待其他的子线程执行结束之后,主线程再终止 t1.join() t2.join() end_time = time.time() print(f'耗时:{end_time-start_time}')以上代码运行后,打印出来的时间在2点零几秒:
NMAP是一款开源的网络探测和安全审核的工具,他能够快速的扫描出某个服务器对外暴露的端口信息。是在安全测试领域很常见的一个工具。 今天我们用python的模拟实现一个简单版本的端口扫描工具,主要使用到socket模块,socket模块中提供了connect()和connect_ex()两个方法,其中connect_ex()方法有返回值,返回值是一个int类型的数字,标记是否连接成功,0为连接成功,其他数字表示有异常。def connect(self, address: Union[_Address, bytes]) -> None: ...def connect_ex(self, address: Union[_Address, bytes]) -> int: ...第一版:def scan_tools_v1(self): host = input('请输入服务器ip地址:') port = int(input('请输入要扫描的端口:')) sk = socket.socket() sk.settimeout(0.1) conn_result = sk.connect_ex((host, port)) if conn_result == 0: print('服务器{}的{}端口已开放'.format(host, port)) else: print('服务器{}的{}端口未开放'.format(host, port)) sk.close()运行结果:D:\Software\Python\Python39\python.exe D:/MyScripts/study_srripts/SockerTools/nmap_tools.py请输入服务器ip地址:8.129.162.225请输入要扫描的端口:8080服务器8.129.162.225的8080端口已开放缺点:1、一次只能扫描一个端口第二版:(支持扫描多个接口)def scan_tools_v2(self): host = input('请输入服务器ip地址:') ports = input('请输入要扫描的端口范围,格式0-65536:') port_start, port_end = ports.split('-') count = 0 for port in range(int(port_start), int(port_end)+1): sk = socket.socket() sk.settimeout(0.1) conn_result = sk.connect_ex((host, port)) if conn_result == 0: print('服务器{}的{}端口已开放'.format(host, port)) count += 1 sk.close() if count == 0: print(f'服务器{host}的{ports}端口均未开放')输出结果只输出已开放的端口信息,如果输入的端口范围中,没有一个端口开放,那么就直接输出端口未开放。总结:1、以上只是一个简易的版本,如果扫描服务器全量端口的话,耗时较长,后面可以考虑用多线程的技术再进行优化。2、代码中针对异常输入未进行校验,可以优化3、要注意ip为字符串类型,端口为int类型,socket对象初始化要放到循环里面,并且要设置超时时间,不然默认的连接要好长时间才返回结果。
在前面的文章中,介绍过如果使用socket进行客户端与服务端的通信,接下来介绍socketserver模块,可用于多客户端与服务端通信。由socket模块换成socketserver模块后,改动不大,主要是服务端的代码要进行改动,客户端的代码基本不用动。服务端要继承BaseRequestHandler类。这个类在初始化的时候,它会依次调用3个方法。子类可以覆盖这些方法。BaseRequestHandler类中的3个方法对应的源码如下:server端代码:import socketserver class mySocketServer(socketserver.BaseRequestHandler): def handle(self) -> None: # 每一次请求处理的时候执行 while True: # 接收客户端数据 client_data = str(self.request.recv(1024), encoding="utf-8") print("{} send:".format(self.client_address), client_data) if client_data in ['quit', 'exit']: print("connection lost") break # 发送数据 send_data = input('请输入消息给' + client_data + ':') self.request.sendall(send_data.encode('utf-8')) self.request.close() def setup(self) -> None: # 每一个连接初始化的时候执行 print("before handle,连接建立:", self.client_address) def finish(self): # 每一个连接清理 pass ip_port = ("localhost", 9999) server = socketserver.ThreadingTCPServer(ip_port, mySocketServer) server.serve_forever() #server.handle_request() #只接受一个客户端连接client端代码:import socket ip_port = ('127.0.0.1', 9999) # 1、创建socket对象 sk_obj = socket.socket() # 2、连接服务端 sk_obj.connect(ip_port) # 3、发送数据 while True: send_data = input('请输入要发送的数据:') sk_obj.sendall(send_data.encode('utf-8')) # 4、接收服务端数据 server_data = sk_obj.recv(1024).decode('utf-8') if server_data is None or server_data == '': break print("接收到客户端的数据", server_data) # 5、关闭socket sk_obj.close() 可以将client端的代码copy一份,命名为不同的文件名,然后一次启动server,client1,client2的脚本,就可以实现客户端和服务端的通信。并且在代码中加入循环后,就可以实现不停的对话,知道输入exit或者quit指令才会退出通信。运行效果:今天先简单介绍一下socket通信的基本操作,至于后面在测开的平台中如何去使用这些技术,敬请期待后面的分享,待我学会了之后继续为大家分享~ 学习过程中遇到问题,可以加V:xiaobotester 一起探讨。
今天分享一份来自某某微信交流群里面一个小伙伴整理的面试题,然后以我这个没正儿八经做过自动化的测试从业点点点工程师来谈一下自己如果遇到这类面试题的答题思路:接口自动化面试题1、接口自动化流程怎么做的,框架怎么搭建的?流程: 1、分析需求,确定测试范围 2、搭建自动化测试环境、准备相关测试数据 3、工具选型,搭建测试框架 4、编写用例 5、执行用例,生成测试报告 6、持续集成框架怎么搭建: 如果是选择用现有框架的话,可以选择postman、jmeter、Robotframework等框架,也可以基于一些开源的框架平台上再去进行二次开发,比如httprunner等,觉得都用不习惯的话,可以考虑自己写代码封装新的框架。看这套面试题,求职者应该回答的是自己写代码的方式。 自己框架搭建要考虑的问题: 1、用例怎么存储,编写是否方便,易用性怎么样,学习成本高不高 2、用例执行执行,日志,报告等如何查看 3、断言如何设计,用例执行失败怎么处理等 4、多人协作怎么管理代码等2、你们公司没有通用的接口自动化框架吗?为什么还需要你们部门来搭建这套。开源框架有开源框架的好处,但是也存在一些问题,有些数据处理起来没这么方便,易用性方面使用起来也不一定很方便,需要一定的学习成本。每个部门的业务场景不一样,开发平台/工具主要还是从成本以及解决某个实际问题的方便去考虑。3、接口自动化回归过程中有没有发现什么问题?取得了怎么样的效果和收益? 比如有时候,开发改某个需求,改动了一些公共的代码之类的,就有可能影响到其他的接口,如果之前稳定的接口已经写好用例的话,这种情况下就能快速的验证出来改动是否有问题。 效果和收益的话,可以说一下接口自动化做起来之后,之前手动回归的功能现在变成自动回归了,节省了多少人力/时间。4、接口自动化搭建和落地过程中遇到什么问题? 用例怎么存储更方便,怎么样设计才能使得编写用例的时候方便,有没有什么办法自动生成用例,用例之间的依赖和数据传递怎么做,用例是否要区分环境,有些用例如果只能在测试环境执行,线上不能执行的,如何区分。怎么样设计能够支持快速切换到其他不同的平台上面去。5、最难的技术难点是什么? 动态变量参数化、接口依赖及中间变量问题、异步接口结果验证问题、相应参数化及嵌套很多的验证问题、接口测试框架的稳定性问题、多接口场景问题、多线程并发、多项目以及不同人员并发操作的情况。6、你们持续集成是怎么做的?持续集成的话,一般都是跟部署结合一起一起使用,比如测试环境更新后,自动触发用例执行。另外,可以设置每晚定时自动构建。7、还有哪些可以优化的点?8、代码结构分层是怎么样的?9、有了jmeter等开源的接口自动化平台,为什么还要代码来做自动化?哈哈,这个也是我想问那些自己写代码做自动化的,以及现在的一些培训机构教的java或者python自动化的模式,为什么不选用开源的框架或平台。其实,大家都心知肚明,自己写脚本写框架,更能体现你的水平,能够拿到的薪资更高。自己写代码,在一定程度上,可以省去对工具的学习成本,虽然说工具的使用不难,但是要把工具用好也不容易,并不是只有写代码才能体现出你的能力。而且,写代码之前,要先了解一下现有工具的一些功能,看下有没有必要自己写代码封装框架。10、你主要负责参与哪部分框架搭建,你们怎么合作共享代码的?代码传递的话,一般都是通过git仓库去管理,然后再通过分支去管控,这个可以参考开发的代码分支管理。11、数据驱动,关键字驱动怎么做的? 数据驱动的话,有相应的包直接可以支持。关键字驱动的话,可以参考Robotframework框架,我所理解的关键字驱动,其实就是一种代码约定。12、这套框架覆盖了开发多少代码量,怎么统计的? 如果是统计代码覆盖率的话 ,一般都会用到相关的插件去进行统计,比如jacoco13、总共多少测试用例,执行一次要多久,覆盖多少接口?这个属于用例设计方面,主要考察你对项目的理解 ,对用例设计的把握,用例设计的覆盖度。14、接口关联怎么处理的?可以将依赖接口返回的数据存到一个项目级别的全局变量里面,然后在用例里面去识别某种特定格式的写法,按照变量去进行处理。15、接口鉴权怎么做的? 鉴权的话一般接口需要传token或者签名之类的,发送接口请求的时候才会校验通过。前几天看一位大佬分享的测开平台的设计,鉴权的话可以考虑绑定在接口域名级别,不用每个case都去单独处理一遍。16、数据参数化,数据驱动,excel读取数据怎么做的? 参数化的设计可以参考postman、jmeter的方式去进行处理。excel读取数据也有专门的库去进行操作,之前在网上看到别人写的一个读取excel的代码,不是一次性将数据都读取出来,而是使用yield关键字去进行处理。还有就是用例设计的时候,是考虑将数据放在一个页签,还是分不同的页签去处理,这个涉及到框架层面以后每加一个页签是否都需要改动代码。17、数据库什么时候去校验的,哪些场景使用到了? 进行接口断言或者是做一些初始化数据准备或者数据清理的时候,就有可能需要去操作数据库。18、接口自动化数据传递方式及区别? 这里我理解的应该是在考察发送请求的时候,数据放在params、data以及json参数中的区别。 看完这样一套面试题,不知道小伙伴们心里有什么感觉呢?是觉得接口自动化简单还是复杂呢?。给我的感觉就是:有些东西做过就是做过,没做过的话,对于有经验的面试官,你没有那么容易蒙混过关,你会发现这些面试题都是一环套一环的,不是随便背几个面试题就可以应聘上专职自动化的岗位。以上所写仅供参考,大家如果有其他的文章或者面试题等,也可以发给小编哟。学习交流可以添加我的微信哟!
大家都知道,HTTP协议是非持久化的,单向的网络协议,在建立连接后只允许浏览器向服务器发出请求后,服务器才能返回相应的数据。缺点就是会导致过多不必要的请求,每一次请求、应答,都浪费了一定流量在相同的头部信息上。然而WebSocket的出现可以弥补这一缺点。在WebSocket中,只需要服务器和浏览器通过HTTP协议进行一个握手的动作,然后单独建立一条TCP的通信通道进行数据的传送。WebSocket是双向通信协议,模拟Socket协议,可以双向发送或接受信息。HTTP是单向的。 Socket是传输控制层协议,是为了方便使用TCP或UDP而抽象出来的一层,是位于应用层和传输控制层之间的一组接口。WebSocket是应用层协议。接下来让我们一起来了解一下在python里面是如何使用Socket进行编程的。Socket通信流程:1、服务器根据地址类型、socket类型、协议创建socket对象2、服务器为socket绑定ip地址和端口号3、服务器socket监听端口号请求,随时准备接收客户端发过来的连接请求(这时候socket并没有被打开)4、客户端创建socket5、客户端根据服务器ip地址和端口号试图连接服务器socket6、服务器socket接收到客户端socket请求,被动打开,开始接收客户端请求,直到客户端返回连接信息。这时候socket进入阻塞状态,即accept()方法一直等到客户端返回连接信息后才返回,开始接收下一个客户端连接请求7、客户端连接成功,向服务器端发送连接状态信息8、服务器accept()方法返回,连接成功9、客户端向服务端socket写入信息/服务端向客户端写入信息10、服务端读取信息/客户端读取信息11、客户端和服务端关闭连接Socket通信模型python代码实现socket服务端和客户端通信# socket_server.py import socket ip_port = ('127.0.0.1', 1234) # 1、创建socket对象 obj = socket.socket() # 2、绑定ip port obj.bind(ip_port) # 3、开启监听 obj.listen() print('服务端已启动') # 4、等待连接 、返回套接字和客户端ip地址 conn, address = obj.accept() print('客户端地址:', address) # 5、接收客户端数据 receive_data = conn.recv(1024).decode('utf-8') print("接收到客户端的数据", receive_data) # 6、发送数据 send_data = input('请输入要发送的数据:') conn.sendall(send_data.encode('utf-8')) # 7、关闭socket conn.close()# socket_client.py import socket ip_port = ('127.0.0.1', 1234) # 1、创建socket对象 obj = socket.socket() # 2、连接服务端 obj.connect(ip_port) # 3、发送数据 send_data = input('请输入要发送的数据:') obj.sendall(send_data.encode('utf-8')) # 4、接收服务端数据 server_data = obj.recv(1024).decode('utf-8') print("接收到客户端的数据", server_data) # 5、关闭socket obj.close()注意:发送的数据格式要进行编码,接收后要进行转码操作。然后先后运行socket_server.py和socket_client.py文件,就可以实现客户端和服务端的通信,脚本运行结果如下:以上只是socket的一个最最最简单的用法,包括一些概念也是从网上各种查找资料进行整理,对概念的理解还不够深入,后续看视频更深入的理解之后再进行补充。有问题都可以在知识星球或者添加小编微信提问喔,有想进学习交流群的也可以添加微信。具体方式在公众号菜单处可以看到。
为大家分享一份来自某个微信群的小伙伴去面试的时候被问到的面试题,希望对大家有帮助。1、自我介绍 介绍你叫xxx,从哪个学校毕业,目前从事测试行业工作xx年,先后就职于某某公司,主要接触过xxx、xxxx的测试(这里可以说是web端、app端、小程序或者H5、客户端等)。2、你们公司的测试工作流程 这里主要想了解一下之前公司的工作流程,从介绍的过程中也可以了解到求职者对公司流程的了解深度。 这个流程包含很多的细节,需要结合公司具体的实际情况去回答,要描述到的点可以包括:需求的管理、提测的流程、上线的流程、源码的管理方式等。这里也建议测试人员多关注一下开发的代码分支是怎么管理的,有时候能直接从流程上去发现和避免一些问题的发生。3、接口测试怎么做的 流程方面可以按照平常怎么测功能的这个流程去描述,比如分析需求提取测试点,制定测试计划,编写接口测试用例,执行用例生成测试报告,接口测试持续集成定时触发构建,并结合测试环境更新后自动触发等。 接下来介绍接口测试用例的一些常见的考虑事项,可参考:接口测试用例测试点 。然后再介绍一下自己所选用的技术,比如用了什么开源框架去做接口测试,或者自己编码写的框架是怎么样去设计的,都可以简单介绍一下。4、印象中的bug 这个是经常被问到的一个问题,按照自己的实际情况回答即可。分享一个我之前回答过的:那些让我印象深刻的bug 5、如果给到特别多的需求,只有你自己做,你要怎么安排,如果每个产品经理都说非常着急呢 这种情况在工作中也会经常遇到,一个人可能手上同时有很多待测试的需求,这种可以考虑自己排优先级,或者提供用例让其他小伙伴帮你测一部分,自己在辛苦一下加加班完成,如果经常出现这种情况,那就要考虑分工是否合理,是否需要新加人员投入,或者针对重要项目/模块进行人员备份,平常多组织需求串讲,让大家都了解一下相关需求,这样在紧急时刻也能帮上忙。 另外,要注意的就是,事情特别多的时候,自己要把待办事项列出来,避免到时候因为自己的疏忽忙着忙着把其他工作给忘记了。比如可以在钉钉上记一个待办事项。6、让你测试搜索,你怎么测试 用例设计的时候,除了保证正常的搜索功能,不同的查询条件组合测试,还得考虑搜索的关键字是否有什么权重因子之类的因素,比如搜索xxx的时候,一定要把某某某的结果放最前面,还有一些关键信息的匹配到,搜索的活跃度等,看下是否都要考虑进去。7、fidder你只是用来抓包吗?除此之外呢,你说使用jmeter测试,为什么还需要使用到fidder 首先,fiddler虽然是一款抓包工具,但是他的作用不仅仅只是抓包,比如弱网,mock等其他场景都可以派上用场。 在没有接口文档的情况下,jmeter做接口测试的时候,就需要用抓包工具了查看接口请求了,或者用fiddler的一个插件,直接导出jmeter脚本。fiddler导出jmeter脚本8、你平常用python是怎么做接口测试的 可以先介绍一下自己框架的技术栈,比如用的python+requests发送请求,用xxx记录日志,用xxx生成报告,用xxx断言等。然后介绍一下用例是怎么管理的,比如存excel/yaml文件或者数据库,然后再介绍一下最终是怎样去运行脚本,执行的计划。9、你最近这个项目主要做什么模块 这个结合自己负责的项目介绍即可。可以介绍自己负责哪些模块,然后在哪些模块有用到一些什么测试技术啥的。10、app测试和web测试的区别 可以从测试的方法、工具、兼容性、专项测试等差异去进行对比分析。11、token cookie session 的区别 要了解这3个的用途,以及差异。存储位置以及安全性等。12、你们有评审吗 如果有评审的话,可以介绍一下流程。13、测试用例怎么编写的,你举个例子。postman,jmeter接口都是怎么交互的。 可以说一下自己平常写用例的一些方法,并结合自己项目的案例进行说明。14、你说比postman更喜欢使用jmeter,为什么? postman和jmeter的使用场景是不一样的15、了解我们的产品吗?就我们产品的登录界面设计一下测试用例 登录的用例设计网上大把,面试前的话 ,对公司的相关情况最好做一下简单了解。16、你们版本迭代周期是多久 介绍一下自己公司项目迭代周期,一般多久发一次版本。比如一周一次,或者两周一个版本。17、你们项目组的成员,测试有多少,开发有多少,公司有多少人 测试有30人,开发有xxx人,公司共有xxx人,部门有xxx人。18、接口自动化你是上班的时候去做,还是下班的时候 上班和下班时间段都可以做,这里更多的是想了解你是怎么去执行用例的,有没有做持续集成,定时的去执行用例。 19、有什么想问我的吗 可以问一下公司的测试团队规模,如果应聘上的话,今后主要从事的工作或者业务是什么,团队的氛围,晋升的空间等。大家平常有什么问题也可以在知识星球上搜索【软件测试交流圈】,然后进行提问喔。学习过程中有什么问题,也可以添加我的微信互相交流学习,WX:xiaobotester 。
Cypress环境搭建Cypress系列-使用yarn命令搭建cypress自动化测试环境Cypress系列-使用npm命令搭建cypress环境编写第一个测试脚本在cypress的项目目录下,在integration文件夹下创建一个first_test_demo.js文件,写入如下内容:describe('My First Test', () => { it('Does not do much!', () => { expect(true).to.equal(true) }) })然后在命令行窗口执行npx cypress open命令启动cypress,在弹出的窗口中点击自己编写的测试脚本文件,运行后结果如下:脚本执行结果:接下来再复制下面的脚本,测试一下执行失败的场景:describe('My First Test', () => { it('Does not do much!', () => { expect(true).to.equal(false) }) })将上面的脚本追加到之前的脚本后面,执行脚本的报告如下:编写第一个打开网站的脚本可以使用以下的脚本去进行操作:cy.visit('url') #打开网址 cy.contains('content').click() #查找元素,然后进行点击完整的脚本如下:describe('第一个打开网站的case', () => { it('finds the content "type"', () => { // 打开网址 cy.visit('https://example.cypress.io') // 查找页面包含type的元素 cy.contains('type').click() // 检查当前页面url是否包含 '/commands/actions' cy.url().should('include', '/commands/actions') // 获取一个输入框,然后输入内容,并且校验内容是否更新 cy.get('.action-email') .type('fake@email.com') .should('have.value', 'fake@email.com') }) })运行后页面截图如下:
Anaconda是什么?Anaconda指的是一个开源的Python发行版本,其包含了conda、Python、Jupyter Notebook等多个科学包及其依赖项,在科学计算和数据分析方面搭建环境运用的比较多。Anaconda环境搭建Anaconda官网下载地址:https://www.anaconda.com/products/individual下载安装包后,双击安装包进行安装。安装时,需要磁盘空间预留3G的样子存在安装后的文件。windows系统下直接双击,然后一直不停的点下一步进行安装即可。验证安装结果:可选以下任意方法:1、“开始菜单 → Anaconda3(64-bit)→ Anaconda Navigator”,若可以成功启动Anaconda Navigator则说明安装成功。启动成功后的页面:2.“开始菜单 → Anaconda3(64-bit)→ 右键点击Anaconda Prompt → 以管理员身份运行”,在Anaconda Prompt中输入conda list,可以查看已经安装的包名和版本号。若结果可以正常显示,则说明安装成功。可以在Anaconda Prompt的窗口中输入jupyter notebook命令,会启动一个网页的服务,可以在线编写笔记,运行python脚本:写入一个打印语句,然后页面运行一下:(这个是通过本地python的pip install jupyter notebook启动的网站执行结果)通过anaconda启动的jupyter notebook遇到的问题:通过anaconda里面启动的jupyter notebook,打开的python环境运行脚本后,执行print()函数,没有输出内容。尝试过升级插件版本,还是没有解决,后续如果解决了再告知原因。
cookie和session的区别?会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。cookie通过在客户端记录信息确定用户身份,session通过在服务器端记录信息确定用户身份区别:1、数据存放位置不同:cookie数据存放在客户的浏览器上,session数据放在服务器上。2、安全程度不同:cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session。3、性能使用程度不同:session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie。4、数据存储大小不同:单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie,而session则存储于服务端,浏览器对其没有限制。自动化测试中用例依赖的数据如何构造?不管是接口自动化还是ui自动化都会存在自动化case依赖数据如何构造的问题,可以从三个方面去考虑:第一个是在测试前采用接口去构造需要的数据;第二个是使用初始化sql去初始化数据,但是如果说表结构复杂的话,sql编写也是比较大的工作量;第三个方式是提前准备好一套数据,并且将该数据对应的数据库进行备份,在之后每次执行测试前先备份当前数据库数据,再导入之前的测试数据,再执行测试,测试执行完后再恢复原有的数据。可参考之前写的文章:如何构造测试数据?接口测试时碰到接口重定向如何去测试?首先接口测试方式不同则处理方式不同,如果用的jmeter则无需特殊处理,jmeter默认会自动处理重定向接口,自动发起对重定向的接口地址的访问并返回结果;如果是采用代码框架的方式则有可能需要特殊处理,拿到第一个接口响应header中的location字段对应的接口地址,发起对该地址的请求。感兴趣的朋友可以自己用以下的网址访问去测试一下各种方式发请求是否有区别:https://www.360buy.com,浏览器访问这个网址会自动跳转到京东首页。用python代码发请求的话,默认allow_redirects=True,会自动重定向,可以手动传Flase进去,然后看一下响应结果。可能其他框架有的没有做这种处理,测试的时候要注意一下。接口依赖第三方接口,但是第三方接口却有问题怎么办?一般会采用mock来解决这个问题。但是要分场景去看是否要开发的支持,如果是客户端直接调用第三方接口的,这种测试人员自己mock就行。如果是开发人员自己包装了一个接口,然后再自己的接口里面再去调用第三方接口的,这种就需要开发的配合才行,将自己公司的接口调用指向mock出来的接口服务。web自动化中有哪些场景需要特殊处理?1. iframe元素,当要操作的元素在iframe中是需要先将driver切换至该iframe才能操作,切换方式有四种,通过id、name、索引、iframe元素对象,并且在多iframe切换时还需要进行各种转换2. 新窗口打开,当要操作的元素在一个新窗口打开的页面上时,就需要先将driver切换至新窗口上才能进行操作3. 时间控件,通常时间控件只能选择无法输入,那么可以采用js的方式修改时间控件的只读属性然后再进行输入,或者用js直接修改时间控件的readonly 属性。参考代码:document.getElementById("xxx").removeAttribute("readonly")4. 元素不在当前视野需要滚动才会出现,可以采用js的方式滚动,但是有时候界面中有多个滚动条js就会无效,则需要先将光标置入到滚动条区域然后模拟键盘的上下左右键来操作.
litemall 是一个以SpringBoot + Vue管理员前端 + 微信小程序用户前端 + Vue用户移动端组成的一个小商城,gitee上Star有6000+,不考虑相关中间件的情况下,项目采用的技术比较接近企业用的一些基本技术。对于自学软件测试或者参加培训,找不到合适的项目写简历上,以及平常自己学习,找不到合适的项目练手的,都可以用这个项目搭建在本地练手。初学者,自己自学的过程中很容易走弯路,比如经常在那自己折腾虚拟机以及各种环境就要折腾大半天,其实在我看来这个还是没必要的,没必要非得在linux上去部署,以我工作7年的经验告诉你们,你们大部分在虚拟机上折腾的这些东西,在工作中基本上用不到,或者很多东西其实都是现成的,不会让你们从头开始去弄,如果非要学习的话,小白就买一个阿里云服务器就好了,新人买个1-3年,费用也不贵,最起码不用去折腾各种什么xshell连接不上虚拟机的问题,这些相关的操作等你入了行,对这个行业有了更多的认知之后,回过头再去学这些,会比较容易接受一点,现阶段,作为测试人员,能够掌握自己在本地windows或者mac电脑上对常用的软件操作熟练就可以了。接下来简单讲一下在本地怎么去搭建litemall商城用来学习使用,,当然,具体的部署教程,一般的开源项目上都有写,你如果看别人的文档能够直接看懂当然是最好,看不懂的朋友,可以再试试看这篇文章。准备工作:电脑本地git环境搭建 Git环境搭建java环境搭建 Java环境搭建maven环境变量配置 Maven环境搭建nodejs环境搭建 Node.js环境搭建代码下载:代码地址:https://gitee.com/linlinjava/litemall找一个目录,然后鼠标右键,选择Git Bash Here,在弹出的窗口中输入如下命令:git clone https://gitee.com/linlinjava/litemall.gitmaven修改mirrors镜像地址修改目的:加快后台代码jar包下载,提升打包效率修改方式:进入到maven安装的目录后,找到conf文件夹,然后找到里面的settings.xml,用文本文件打开进行编辑:大概在140多行的样子,或者搜索mirrors标签,然后加入如下的配置:<mirror> <id>nexus-aliyun</id> <mirrorOf>central</mirrorOf> <name>Nexus aliyun</name> <url>http://maven.aliyun.com/nexus/content/groups/public</url> </mirror>修改后的内容截图如下:创建数据库以及导入数据进入到从gitee上下载好的代码文件夹中,然后进入到litemall-db\sql目录下面,依次执行下面的sql文件:1、litemall_schema.sql 执行后会自动创建一个litemall的数据库,如果数据库已存在,则会删除重建2、litemall_table.sql 选择litemall数据库后,执行改脚本,会自动创建项目中用到的表3、litemall_data.sql 选择litemall数据库后,执行该脚本,会导入初始化测试数据,其中包括前端登录的用户账号代码打包编译需要进行打包的操作如下:后端代码打包&本地启动打包:先进入到代码的根目录,也就是最外层的pom.xml文件所在的目录,打开cmd窗口(在windows的文件管理器中输入cmd回车),执行以下命令打包后端代码:mvn -U clean install执行完命令后,会看到很多SUCCESS则表示打包成功:这里打包的命令用mvn install / mvn package均可,-U 以及clean 参数不加问题也不大。打完包后,在litemall-all目录下的target文件夹中会有一个xxx-exec.jar的可启动jar包,这就是打好的部署包,在litemall-all-war文件夹下也会生成一个war包,不过war包我没有试过能不能部署,感兴趣的可以自己去试试。本地启动后端的服务cmd窗口执行java -jar xx.jar的方式就可以启动服务。进入代码根目录后,执行下面命令 chcp 65001 java -Dfile.encoding=UTF-8 -jar litemall-all/target/litemall-all-0.1.0-exec.jar 以上第一行不加的话,控制台日志输出可能会是乱码执行后的效果如下:如何验证是否启动成功:打开浏览器,访问http://127.0.0.1:8080/swagger-ui.html页面,能出现以下内容则表示后端部署成功:如何快速验证部署有没有问题,能不能连接上数据库:方式1:curl -X POST "http://127.0.0.1:8080/wx/auth/login" -H "accept: */*" -H "Content-Type: application/json" -d "{\"username\":\"user123\",\"password\":\"user123\"}"方式2:直接在swagger页面输入账号密码调用登录接口:然后在wx-auth-controller下面找到/wx/auth/login接口,输入下面的参数进行调用:{"username":"user123","password":"user123"}说明:之所以要右上角切换wx分支,是因为wx分组的登录接口不需要验证码,admin分组的登录接口要验证码,稍微麻烦点。到此,一个完整的后端服务就部署成功了,到这里就可以用这个swagger文档进行接口测试实战了,接下来再看一下如何部署后台管理系统和前端页访问页面。本地启动后台管理系统前端进入到代码litemall-admin目录,执行以下命令:npm install -g cnpm --registry=https://registry.npm.taobao.org cnpm install cnpm run dev执行完后,最终效果如下:登陆后页面效果如下:本地启动前端商城页面进入到代码litemall-vue目录,执行以下命令:npm install -g cnpm --registry=https://registry.npm.taobao.org (此命令之前执行过可不再重复执行) cnpm install cnpm run dev执行后效果:前端登录用户默认为user123 密码user123到此,此套商城基本上就部署的差不多了,还有一个是微信小程序的,这个我也暂时还没学会怎么部署,对于小白进行项目实战来说,部署完以上我写的这个足够了。往期环境部署相关文章:Jenkins自动部署测试环境之jar包部署你们要的测试练习网站来了文章写的不易,有收获的朋友帮忙分享一下。关注公众号,后面教你怎么将开源项目写到简历上,以及如何用这个项目来开始你的小白转行入门之路以及技术提升之路,欢迎进群交流哟!
传统的java项目是什么模式? 在我读大学那会,那个时候学java,用java来开发项目的话,一般都会在自己项目下新建一个libs的文件夹,然后把所需要用到的第三方jar包放到libs目录下面去,并且以后的项目大都是前后端未分离的模式,项目成员之间要共享代码的话,这些第三方的jar包都要传到git或者svn仓库上去,这样会导致仓库里面项目文件大小非常庞大,也不便于对jar包版本的管理。 maven是什么? maven一个jar包的依赖管理工具。直到第一份工作,在工作中接触到了maven,才发现它的好处。有了maven之后,再也不用在项目中上传jar包进去了,只需要在一个pom.xml格式的文件里面配置好每个jar包的名称和对应的版本号就行,编译的时候会自动从仓库去下载所需要的jar包到自己本地,pom.xml中对单个jar包的配置格式如下所示:<!-- https://mvnrepository.com/artifact/org.testng/testng --> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>7.4.0</version> <scope>test</scope> </dependency>maven的官方仓库地址:https://mvnrepository.com ,可以在这个上面搜索需要的jar包,然后就可以看到对应的相关依赖直接复制即可。maven下载 and 环境变量配置因为maven是用来管理jar包的,因此,需要先在本地配置好jdk的环境!!!可参考: Java环境搭建官网下载地址:http://maven.apache.org/download.cgi公众号后台回复 工具/tools也可获取相关工具下载地址。工具下载好后,是一个压缩包,先解压。我这里解压后的目录是:D:\Software\apache-maven-3.8.1 ,接下来配置环境变量:win10电脑:我的电脑--右键属性--高级系统设置:然后点击环境变量,然后在系统变量下面新建一条记录:变量名写MAVEN_HOME,变量值写解压后的目录:(变量名可以改其他名称,但建议用这个)然后再系统变量下找到PATH,点击编辑:然后新建一条记录,输入%MAVEN_HOME%\bin ,最终如下图所示:配置好后,点击确定,然后打开cmd窗口,输入mvn -v,如果显示maven的版本号,则maven环境安装成功:其实就是要把解压后目录下的mvn所在目录加入到环境变量PATH中即可:注意事项:1、打开cmd窗口输入mvn命令时,一定要先配置好环境变量,然后重新打开cmd窗口才行。2、如果win10电脑上PATH环境变量的值不是分多行显示,而是显示成一行,印象中是因为第一个路径没有以C盘开头导致。maven如何使用?在java编写的maven工程的代码中,一般都会有一个pom.xml的文件,在那个文件对应的目录打开cmd窗口,然后执行maven的命令就可以进行编译、打包等操作。要注意的是,代码里面可能存在多个pom.xml的情况,可以优先在最外层的pom.xml文件目录执行命令即可。常见的几个命令大家可以先去自学一下:mvn -U clean compile mvn install mvn package mvn deploy
为什么要使用PO模式?PO是Page Object 模式的简称,它是一种设计思想,意思是,把一个页面,当做一个对象,页面的元素和元素之间操作方法就是页面对象的属性和行为,PO模式一般使用三层架构,分别为:基础封装层BasePage,PO页面对象层,TestCase测试用例层。Page Object是一种程序设计模式,将面向过程转变为面向对象(页面对象),将测试对象(按钮、输入框、标题等)及单个的测试步骤封装在每个Page对象中,以page为单位进行管理。这样,在Selenium测试页面中可以通过调用页面类来获取页面元素,从而巧妙的避免了当页面元素id或者位置变化时,需要改测试页面代码的情况。当页面元素id变化时,只需要更改测试页面文件类中页面的属性即可。可以使代码复用,降低维护成本,提高程序可读性和编写效率。POM解决的问题:以页面为单位,集中管理元素对象和方法。当页面元素或流程变动时只需要修改相关页面方法即可,不需要修改相应脚本,后期维护方便 。PO模式是一种设计思想,在实际编码的时候可以有若干种实现方式。实际上,也建议大家根据自己项目的情况来动态的编码。具体来说,常见的PO模式有:1)三层:对象库层+case层+page层2)四层:对象库层+case层+page层+公共类接口测试用例的编写要点有哪些?考点:接口测试用例设计参考答案:1)必填字段:请求参数必填项、可选项2)合法性:输入输出合法、非法参数3)边界:请求参数边界值等4)容错能力:大容量数据、频繁请求、重复请求(如:订单)、异常网络等的处理5)响应数据校验:断言、数据提取传递到下一级接口… 6)逻辑校验:如两个请求的接口有严格的先后顺序,需要测试调转顺序的情况7)性能:对接口模拟并发测试,逐步加压,分析瓶颈点8)安全性:构造恶意的字符请求,如:SQL注入、XSS、敏感信息、业务逻辑(如:跳过某些关键步骤;未经验证操纵敏感数据)接口测试中的加密参数如何处理考点:是否熟悉加解密方式是否具备处理加密参数的能力是否实际应用过参考答案:首先了解参数的加解密方式,常见的有md5、aes、rsa等等,如果是aes的需要找开发要私钥,如果是rsa需要找开发要公钥和私钥,然后在接口测试工具中引用加解密的代码实现参数的加解密过程,实现参数加解密的处理;如果公司有自定义的加密算法则需要找开发要加解密的代码实现,然后在测试工具中使用。同步和异步区别?同步和异步是一种通讯方式同步:执行一个操作时,需要等待其处理完成,然后再进行下一个操作异步:执行一个操作时,不需要等待返回,就可以进行下一个操作举例:下单接口中,需要调用库存接口做库存判断,所以必须等待库存接口返回数据才能进行下一步操作,这是同步; 文件的下载方式,我之前就经常遇到需求说让开发改成异步下载。避免下载比较慢会导致超时,并且影响用户体验。简单介绍一下自动化项目整体框架的结构自动化测试框架涵盖基础方法封装、自定义异常封装、工具类封装、元素管理封装、Page Object模式封装、日志封装、数据管理封装、失败重试封装、浏览器/手机适配封装、数据库操作封装、测试用例管理封装、测试报告等等。简述Jmeter工具如何做接口之间的关联?接口关联指的就是一个接口要使用另一个接口的返回值作为参数,这种我们在jmeter中叫做关联。关联的实现方式有多种:1、使用正则表达式提取器获取上一个请求的响应结果中的某个值,储存在某个变量中,然后下一个接口使用变量进行引用2、使用json提取器获取上一个请求的响应结果中的某个值,储存在某个变量中,然后下一个接口使用变量进行引用3、使用beanshell后置处理器,解析响应结果存储在变量中,然后下一个接口使用变量进行引用跨线程组关联则需要将关联字段设置为全局属性你们公司业务中,自动化和手工分别占比多少?分别用来做什么业务?首先各公司自动化和手工的占比取决于对自动化测试的投入,这个问题的回答建议做好数据,比如我们的项目共有20个模块,功能测试用例总计1000,从其中分析出要实现的自动化用例300条,那么自动化的占比就出来了。那么哪些测试用例会被用来做自动化:稳定模块的用例、功能优先级高的用例、重要主流程的用例等。手工测试一般用来做新功能测试业务,自动化一般用来做旧的功能用来回归业务。如何保证UI自动化测试的稳定性?自动化测试稳定性主要表现在两个方面:一个是元素定位的问题,一个是用例之间的依赖问题。元素定位问题可以采用智能等待的方式尽可能的避免,另外,优化xpath定位的写法等。用例依赖可以解耦用例之间的关系,让每条用例都从一个共同的页面开始执行,比如首页,这就需要在测试框架中采用后置处理的方式使每条用例执行完成后都回到首页。关注公众号#小博测试成长之路,为你分享小编自己自学和整理的笔记喔。更多面试题/学习交流,在群里等着你呦,公众号后台回复进群/通过菜单自己扫描加群即可。
接下来让我们一起看一下为大家收录的面试题:一、为什么离职?这个问题其实没什么标准答案,可以考虑以下几点:1、地理位置原因,比如公司搬迁、自己在当前城市其他区购房之类,想找个近一点的2、结合自己的职业规划,想找一个更好的平台注意点:不要在面试的时候去抱怨之前的公司、说上司的坏话二、简单sql查询,单表分组聚合怎么使用?这种问题属于sql的基本用法,具体操作不在这里描述,回答问题要注意的点:先介绍分组和聚合会用到哪些关键字,然后要结合具体的按钮去讲一下你在工作中有没有用过这些用法 ,用来做什么处理三、口述99乘法表的编写既然是口述,我觉得肯定只要给出思路就行。说句实话,要我一次性写出来 不能调试,我估计我可能还写不出来,打印这个有几个关键的点:双重循环的控制以及什么时候跳出循环,以及换行。给大家分享一个网上查到的比较装逼的写法:print('\n'.join([' '.join([f"{j}x{i}={i*j}" for j in range(1, i + 1)]) for i in range(1, 10)]))四、自动化测试了解多少,工作中都怎么用的?1、可以先介绍一下你所了解到的自动化的类型,比如UI、接口、运维自动化等2、挑选一种你最熟悉的自动化的类型,进行详细的介绍。比如介绍通过某款工具是实现自动化,或者介绍通过自己写脚本的方式去实现自动化,不管用哪种方式,都离不开用例的设计与存储,日志和报告的查看,持续集成等相关操作 ,整体的流程结合起来一起介绍一下。五、中间件测试了解多少,怎么去测试的中间件?面试既然问到这个问题,那肯定是你的简历上哪里体现了跟这块相关的内容,比如redis、es、kfaka之类的。说实话,这块我也接触的比较少,如果我被问到了,我会按以下的思路去介绍:1、比如介绍缓存和redis,先告诉面试官缓存是怎么设计的,你怎么通过手工/自动的方式去修改里面的数据,从而验证缓存是否生效等2、像kfaka这种,也是类似,可以验证模拟手动往里面推送数据,验证一些从页面不方便模拟的场景。至于其他的一些比较专业的中间件的测试点,大家可以根据自己的简历,在网上查找对应的测试点去进行了解,要注意不要脱离了项目的业务。六、抽奖用例设计:一等奖一个,二等奖两个,三等奖三个,其他都是谢谢,如何测试,用例如何设计?这种就看自己临场发挥了,我觉得这个地方在测试前,要确认本次抽奖券的总发行张数,然后再做测试设计。1、要关注对应奖项是否超过规定的数量2、抽奖结果的枚举值是否都是在一二三等奖与谢谢 中间,不存在其他的文案之类的。3、比如目前还未出现中奖者的时候,并且只剩下6张券的时候,验证是否每张都是必中奖等七、app访问一个网页一直在加载可能原因是什么,怎么排查这个访问慢的问题?1、检查手机网络,是否有丢包等情况2、用手机访问其他网站,确认是否网络问题3、找不同账号、在同一网络情况下用不同的设备去访问同一网站,排查是否是设备兼容性/账号权限等问题导致4、抓包看下是否有报错、app本身是否有报错日志记录等5、检查手机网路是否配置了代理、配了什么拦截响应结果之类的操作八、服务间的数据同步怎么做的,数据同步的准确性怎么保障的?这种应该是根据简历上项目的相关经验问的,我介绍下我接触过的:通过数据库的cdc以及同步工具,比如binlog,然后将数据丢到kfaka消费至于怎么保障数据准确性,这个属于开发层面的事情,做一些监控之类的,然后根据自己项目的具体方案去查一些资料介绍 ,另外,进行数据准确性的测试,按照同步的规则,对源数据和目标数据进行核对。至于怎么核对,可以是人工,也可能是脚本,看具体的场景。九、比如MySQL同步数据到hive怎么做的?一般的数据同步都是通过监听变化,采集 清洗入库,相关流程百度上就有,这个对于测试而言,一般的不需要了解 ,除非你的项目正好用到了这样的技术架构,那面试官可能是想了解一下这个流程,同时也检验一下你在项目中测试的深度,对业务的熟悉程度。这种一般在大数据测试、数据分析&核对的相关工作中出现的会多一些。十、都用python做了哪些辅助测试工作,如何实现的?python作为一门脚本语言,有其自己的优势,除了做自动化之外,平常可以写一些辅助脚本,提升测试效率,这个具体做什么事情,大家根据自己的编程水平与工作经验去回答就行。比如:1、用python+requests调用接口,对返回结果进行加工处理,按指定格式得到自己需要的批量数据。2、开发一些小工具平台,将一些常用的造数据/改数据的脚本集成上去,方便公司内部其他测试人员使用,尤其是那种业务比较复杂的系统,下游经常需要依赖上游造数据的。3、写一些简单的接口调用脚本,定时触发检查线上服务或数据是否有问题十一、接口测试的接口依赖怎么处理的?将依赖接口的返回结果存储起来,供其他接口使用,比如最常见的登录后获取到token 存起来,给其他接口使用。十二、简述TCP请求连接的过程;三次握手四次挥手之类的,百度一下就有答案。十三、性能问题如何定位的,从哪些方面去定位的?看日志和监控,检查数据库、服务器资源等相关状态十四、安全测试都会测试哪些内容,都是怎么测试的?被问到这种问题的,肯定是简历上写了会安全测试,要么就是写了会用一些类似appscan,burpsuit之类的工具。首先要了解常见的安全漏洞有哪些,比如sql注入、跨站脚本攻击、权限越权、敏感信息泄露等,然后针对工具出来的问题要知道怎么通过手动的方式去模拟复现问题,以及如何去回归验证。想一些sql注入,xss ,测试人员在做功能测试的时候,是可以做一些简单的手工测试的。十五、你们怎么搭建的测试环境,对一些中间件的配置是否了解,可以简单的说一下?可以介绍一下公司项目的技术架构,部署包的格式以及流程,顺带介绍一下各个环境的管理等。 那些拿个php电商网站联系的,环境搭建建议就不要写到简历上去了。我之前写过一篇网上找了个开源项目搭建的部分教程,能把那个搭建出来的话还可以考虑写一下。(格式比如jar包、war包、压缩包,部署方式比如 java -jar ,通过tomcat、docker、iis等方式部署)十六、当前薪资是多少,期望薪资是多少?谈到薪资,基本上也就到了面试的最终环节了,这个就按照自己的相关信息去回答就行。一般跳槽的涨幅可能在10~30%左右,超过这个范围,你要能在面试的时候体现出你的优势。
让我们一起看一下为大家收录的面试题:为什么要在一个团队中开展软件测试工作?因为没有经过测试的软件很难在发布之前知道该软件的质量,测试同样也需要质量的保证,这个时候就需要在团队中开展软件测试的工作。在测试的过程发现软件中存在的问题,及时让开发人员得知并修改问题,在即将发布时,从测试报告中得出软件的质量情况。你认为做好测试用例设计工作的关键是什么?1、需求和设计文档的理解程度,对系统的熟悉程度2、用较少的用例覆盖尽可能多的需求,从用户角度出发,颗粒度大小要均匀,测试场景方法,能够被其他测试人员执行3、测试用例的编写要根据测试对象特点、团队的执行能力等各个方面综合起来决定编写策略。最后要注意的是测试人员一定不能抱怨,力争在不断提高测试用例编写水平的同时,不断地提高自身能力现在有个程序,发现在 Windows 上运行得很慢,怎么判别是程序存在问题还是软硬件系统存在问题?1、检查系统是否有中毒的特征;2、检查软件/硬件的配置是否符合软件的推荐标准;3、确认当前的系统是否是独立,即没有对外提供什么消耗 CPU 资源的服务;4、如果是 C/S 或者 B/S 结构的软件,需要检查是不是因为与服务器的连接有问题,或者访问有问题造成的;5、在系统没有任何负载的情况下,查看性能监视器,确认应用程序对 CPU/内存的访问情况。和用户共同在uat测试 ,有哪些需要注意的地方?用户验收测试不通过的话,就可能影响到钱、以及公司的形象,以及作为测试人员的你在领导心中的印象等。实际上用户现场测试更趋于是一种演示。在不欺骗用户的前提下,我们向用户展示我们软件的优点,最后让“上帝”满意并欣然掏出“银子”才是我们的目标。因此用户测试要注意下面的事项:(1)用户现场测试不可能测试全部功能,因此要测试核心功能。这需要提前做好准备,这些核心功能一定要预先经过测试,证明没有问题才可以和用户共同进行测试。测试核心模块的目的是建立用户对软件的信心。当然如果这些模块如果问题较多,不应该进行演示。(2)如果某些模块确实有问题,我们可以演示其它重要的业务功能模块,必要时要向用户做成合理的解释。争得时间后,及时修改缺陷来弥补。(3)永远不能欺骗用户,蒙混过关。道理很简单,因为软件是要给用户用的,问题早晚会暴露出来,除非你可以马上修改。和用户进行测试还要注意各种交流技巧,还要为后面的合作打好基础。 接口测试用例怎么设计?我的理解,这个其实就是在问接口测试用例的测试点1、从功能的角度,考虑正常场景和异常场景2、考虑业务规则的边界以及输入/输出参数的边界,覆盖所有必选参数,组合所有可选参数,以及参数的不同数据类型等3、考虑接口的幂等性(重复提交),并发测试、事务、分布式、环境异常以及大数据量等场景4、查看接口的性能5、考虑接口的安全性相关的内容,是否存在sql注入之类等安全漏洞,敏感信息是否加密返回/不返回什么是系统瓶颈?参考答案:瓶颈主要是指整个软硬件构成的软件系统某一方面或者几个方面能力不能满足用户的特定业务要求,“特定”是指瓶颈会在某些条件下会出现。严格的从技术角度讲,所有的系统都会有瓶颈,因此我们讨论系统瓶颈要从应用的角度讨论:关键是看系统能否满足用户需求。在用户极限使用系统的情况下,系统的响应仍然正常,我们可以认为改系统没有瓶颈或者瓶颈不会影响用户工作。因此我们测试系统瓶颈主要是实现下面两个目的:1、发现“表面”的瓶颈。主要是模拟用户的操作,找出用户极限使用系统时的瓶颈,然后解决瓶颈,这是性能测试的基本目标。2、发现潜在的瓶颈并解决,保证系统的长期稳定性。主要是考虑用户在将来扩展系统或者业务发生变化时,系统能够适应变化。满足用户目前需求的系统不是最好的,我们设计系统的目标是在保证系统整个软件生命周期能够不断适应用户的变化,或者通过简单扩展系统就可以适应新的变化。 列举几个python2和python3区别?1、Python3 使用 print 必须要以小括号包裹打印内容,比如 print('hi')Python2 既可以使用带小括号的方式,也可以使用一个空格来分隔打印内容,比如 print 'hi'2、python2 range(1,10)返回列表,python3中返回迭代器,节约内存3、python2中使用ascii编码,python3中使用utf-8编码4、python2中unicode表示字符串序列,str表示字节序列 python3中str表示字符串序列,byte表示字节序列5、python2中为正常显示中文,引入coding声明,python3中不需要6、python2中是raw_input()函数,python3中是input()函数当面试官告知你你所用的语言和他们公司不一致的时候怎么办?我相信有很多的小伙伴经常会遇到,自己面试的公司用的语言跟自己所学的不一致,比如你用的是java,应聘的公司用的是python,那这个时候怎么办呢,站起身来转头就走吗?1、你可以告诉面试官,语言不是关键,很多框架设计的思想都是相通的,而且要表明自己的态度:只要公司愿意给机会,自己愿意尝试去学习新的语言。事实上,像那些高级开发,在公司根本就不会局限于语言,如果公司有机会,或者项目需要,要用到其他语言的时候,他们有这个能力能在短时间内快速上手。2、平时的话,python和java不管你学的是哪一个,建议对另一个都要有一些简单的了解,可以多跟同行交流一下,看一下在方案设计上是否有可取之处,互相融合。你认为做好测试计划工作的关键是什么?在软件测试工作正式实施之前明确测试的对象,并且通过对资源、时间、风险、测试范围和预算等方面的综合分析和规划,保证有效的实施软件测试;1. 要有明确的测试目标,对被测对象有清晰的认知和了解2.坚持“5W”规则,明确内容与过程“5W”规则指的是“What (做什么)”、 “Why(为什么做)”、 “When(何时做)”、 “Where(在哪里)”、“How(如何做)”。利用 “5W”规则创建软件测试计划,可以帮助测试团队理解测试的目的(Why),明确测试的范围和内容(What),确定测试的开始和结束日期(When),指出测试的方法和工具(How),给出测试文档和软件的存放位置(Where)。3.采用评审和更新机制,保证测试计划满足实际需求 如何减少测试人员跳槽带来的影响?作为测试管理者,只有从日常工作中开始做起,才能最大限度的减少损失。建议我们从以下两个方面做起:1、加强部门内员工之间的互相学习,互相学习是建立学习型组织的基本要求,是知识互相转移的过程。在此基础上,可以把个人拥有的技术以知识的形式沉积下来,也就完成了隐性知识到显性知识的转化。2、通常情况下,企业能为员工提供足够大的发展空间时,如果不是待遇特别低,员工都不会主动离开企业。因此我们要想留住员工,管理者就应该把员工的个人 成长和企业的发展联系起来,为员工设定合理发展规划并付诸实现。不过这项要求做起来比较,要有比较好的企业文化为依托。
面试的准备跟笔试的准备是不一样的,笔试的准备的话,可以去刷题,面试的话,专业的面试官一般首先都会根据你简历上写的内容去提问,都问完之后,最后可能再会问一下简历之外的,或者简历上写的比较模糊的内容。为什么会问简历之外的内容呢?可能想考察一下你的知识面。接下来让我们一起看一下今天一位小伙伴在粉丝群分享的一些面试题:一、你是怎么做自动化测试的。项目组几个人,分工怎么负责,分支代码怎么合并提示:1、可以围绕你是怎么进行自动化工具/脚本的选型进行阐述2、针对自动化测试用例的设计思路进行说明3、针对自动化测试的执行流程,触发场景等进行说明(最好要体现持续集成,然后与持续部署打通)4、说明你们项目组目前自动化的实现程度,都运用在了哪些环境上5、介绍一下组员之间的分工,代码分支的管理,这里的代码分支肯定不止一个,具体可参考开发的代码分支管理的模式二、说说docker常用命令1、先说一下之前自己在工作中接触docker这个主要用来干什么2、介绍在工作中常用到的一些命令,比如与环境部署相关会用到docker pull/ build / exec/ rm /rmi /logs 等 ,按照自己所了解的进行介绍,要注意要知道每个命令在工作中哪些场景会用到,不要光死记硬背命令。三、k8s的pods有几种状态,分别是什么具体的状态百度即可,需了解k8s是什么,简历上不写这个的一般不会被问到。那几个状态的话,简单了解就行。公司没用这一套进行环境管理的可以不用关注这个。四、用过ES和Mongo么,查询语法是什么,他们和mysql的区别。在存储上,mongodb和es是document格式的存储,mysql是行格式的,因此mongo和es并不需要显式定义字段,而mysql需要。在架构上,es天然就是分布式的,这个可以很容易的横向扩容,而mongo和mysql不行。五、说说mysql左连接查询和右连接查询的区别左连接,以左表为参照,显示所有数据;右连接,以右表为参照显示所有数据;六、说说你们的数据流向是什么。这个要根据具体的项目去分析,没有标准答案。可以介绍你们项目的源数据是从哪里来的,要经过什么处理,然后最终输入写入到哪里,后续还会不会再传给其他环节使用 , 不是所有项目都会去问这种面试题,但是跟数据相关的部门或者测试经验,一般会被问到七、说说怎么测试kafka的性能和稳定性的。如果数据流断了,你们有什么补救措施。Kafka系统提供了测试工具kafka-producer-perf-test.sh和kafka-consumer-perf-test.sh,通过该工具可以对生产者性能和消费者性能进行测试八、懂Linux命令么。说说awk和sed的区别。sed的核心是正则,awk的核心是格式化.sed读取一行,以行作为单位,进行处理。awk读取一行,切割成字段,以字段为单位,进行细节处理。九、你们项目中selenium用什么元素定位方法最多,css和xpath区别。PO模式你们怎么做的1、应该是xpath或者css用的多一些,像什么id和name之类的应该用得少,现在前端页面都是用框架开发的 ,一般元素没有id,或者id都是动态的,每次都会随机变化2、2个定位方式的区别的话,可以从表达式的简洁程度、在不同浏览器的响应速度、易用性上面去考虑3、PO模式的话,这里需要介绍PO模式的思路,介绍你是怎么管理页面元素,为什么要这么管理,以及怎么去执行用例和生成报告等十、接口自动化如何做断言1、首先描述要断言的内容:响应时间、状态码、响应值等2、其实结合你选用的框架进行描述,具体是怎么去断言的,是否会涉及到查数据库断言等十一、我看你用过fiddler是吧,怎么用的?如何过滤你不想看到的请求1、fiddler有个Filters可以配置只抓取哪些接口/不抓取哪些接口等2、可以介绍自己在工作中在哪些场景下会需要用到fiddler,结合具体的案例以及对应的fiddler功能去进行讲解,不要就简单的一句用来抓包,要讲清楚为什么要抓包。 比如常见的功能有抓包、弱网、拦截/篡改响应结果,具体的使用场景在我之前的文章中有写到。十二、你负责的项目中在测试周期中,如何做到最好的控制风险或者预估即将可能发生的风险制定好测试计划、要注意及时跟进进展,还要注意内部和外部可能存在的风险点,尤其是依赖外部系统对接的,万一出现延期后要有备选方案。十三、做过性能测试么?说说如何开展性能测试的了解性能需求,确定性能指标搭建性能测试环境、准备数据、压测脚本调试脚本、执行压测脚本、监控出报告、调优、回归验证等写在最后:1、以上问题答案仅供参考,不能当做标准答案去背,欢迎小伙伴后台留言反馈自己的面试题喔,为同行的学习一起添砖加瓦2、粉丝2群已建立,如需进粉丝群/小白学习群一起交流学习的,可以在公号(小博测试成长之路)菜单点击加群即可。群内禁止闲聊与测试无关的话题,如果是抱着吹水摸鱼的心态,请不要进来打扰这一片净土!已经进了1群的小伙伴不要重复进了。3、如需其他学习资料,可在公众号后台回复关键字,如:python、面试等,小编后面会逐步完善自己收藏的资料。整理不易,给个关注点个赞吧,谢谢各位大佬!
简单介绍一下使用pycharm的一些常规操作吧,工具安装之类的就不介绍了。只记录自己偶尔会用到的一些功能。Pycharm支持python的多个版本,可以自由切换python版本执行脚本。下载地址:从官网下载 https://www.jetbrains.com/pycharm激活码:日常使用下载社区版本就行,激活码就不在这里提供了,有需要的话私聊我,发给你们,网站都可以找到的激活码的,过期了重新获取一下就行Tips:1、使用pytharm编写脚本时,记得在.gitignore文件中添加 一行:.idea/ ,添加后,这个目录下的文件将不会上传到git仓库上,避免其他电脑下载你的功能还需要重新配置。如果git仓库中已经上传了.idea文件夹,需要删除后再添加.gitignore文件,不然不会生效2、常用快捷键:Shift + F6: 文件重命名Ctrl + F12: 显示当前文件结构,当文件方法过多时,可以快速选择Ctrl+Alt+S:打开设置页面Ctrl+/:注释快捷键有很多,剩下的可以自己去了解3、Pycharm设置去除显示的波浪线方法一:打开pycharm在右下方有一个医生头像的小图标,点击打开,如下图:但是该方法只针对本文件生效其他文件还是会有相同的问题方法二:1、顶部菜单 file->settings (快捷键 Ctrl+Alt+S)2、选择Editor—Color Scheme—General选项,然后选择右边对话框中的Errors and Warnings选项,选择选项下方的weak Waring,然后将界面右边的Effects去掉勾选即可。如下图:4、设置文件模板 ,设置之后,每次新建py文件的时候,会有一个默认模板,大家可以根据自己的喜好进行调整,这里我用的是这个模板:# -*- coding: utf-8 -*- # Time:${DATE} ${TIME} # Author : 小博 # Description : # WX :xiaobotester大家也可以按照上面的操作新建其他格式文件的模板喔,比如html,xml这些都可以设置模板的。
下面介绍一下在postman中,一些脚本的常见用法:responseBody等价于response.text,表示接口请求的响应体,类型为string,如果返回的字符串是json格式的,可以使用JSON.parse()进行解析。curl --location --request POST 'http://8.129.162.225:8082/account/login?username=demo&password=demo' var type = typeof responseBody // 得到的值是string类型 var res = JSON.parse(responseBody) console.log( type,res.msg,res.data.token)pm.response等价于response对象,包含Body、Code、Status、Cookies、Headers等内容。响应结果断言// 检查接口请求的状态是否为200 pm.test("请求状态码验证", function () { pm.response.to.have.status(200); });// 检查接口响应结果中的内容是否正确(返回json时) pm.test("返回结果内容断言", function () { var jsonData = pm.response.json(); pm.expect(jsonData.msg).to.eql('成功'); pm.expect(jsonData.code).to.eql(20000 ); });// 其他方法: pm.response.to.have.status(code:Number) pm.response.to.have.status(reason:String) pm.response.to.have.header(key:String) pm.response.to.have.header(key:String, optionalValue:String) pm.response.to.have.body() pm.response.to.have.body(optionalValue:String) pm.response.to.have.body(optionalValue:RegExp) pm.response.to.have.jsonBody() pm.response.to.have.jsonBody(optionalExpectEqual:Object) pm.response.to.have.jsonBody(optionalExpectPath:String) pm.response.to.have.jsonBody(optionalExpectPath:String, optionalValue:*)在pm.test()中写入的名称,在测试报告中和输出的时候会体现是哪个环节的校验结果,添加类似jenkins中pipeline的这种step的描述的话,有助于在报告中体现的会更加详细,知道具体是哪一种断言不通过,Test Results中的显示如下:pm对象pm对象在浏览器中使用网页版以及桌面版都可以使用。(书上说浏览器插件无法使用,应该是以前低版本不支持,现在浏览器搜不到那个插件了,可以直接打开网页使用:https://web.postman.co/home)pm.info.eventName:用来获取当前是在Pre-request Script还是Tests中执行的脚本,返回的是字符串“prerequest” 或 “test”。pm.info.iteration:它用来显示当前运行迭代的次数(从0开始)pm.info.iterationCount:返回迭代运行的总次数pm.info.requestName:用于返回请求名,对应postman上请求的名称pm.info.requestId:用于返回请求IDpm.sendRequest对象允许异步发送HTTP/HTTPS请求。① 该方法接受一个兼容SDK的请求和一个回调。回调接收两个参数,其中一个错误(如果有的话),另一个是SDK兼容的响应。② 该方法可以在预请求或测试脚本中使用。// 以普通字符串URL为例 pm.sendRequest('https://postman-echo.com/get', function (err, res) { if (err) { console.log(err); } else { pm.environment.set("variable_key", "new_value"); } }); // 使用完整的SDK请求为例 const echoPostRequest = { url: 'https://postman-echo.com/post', method: 'POST', header: 'headername1:value1', body: { mode: 'raw', raw: JSON.stringify({ key: 'this is json' }) } }; pm.sendRequest(echoPostRequest, function (err, res) { console.log(err ? err : res.json()); }); // pm.test只能在Tests选项卡下使用 pm.sendRequest('https://postman-echo.com/get', function (err, res) { if (err) { console.log(err); } pm.test('response should be okay to process', function () { pm.expect(err).to.equal(null); pm.expect(res).to.have.property('code', 200); pm.expect(res).to.have.property('status', 'OK'); }); });环境变量、变量相关的操作pm.globals对象包含以下方法可供调用: pm.globals.has(variableName:String) → boolean pm.globals.get(variableName:String) pm.globals.set(variableName:String, variableValue:String) pm.globals.unset(variableName:String) pm.globals.clear() pm.globals.toObject() pm.environment对象包含以下方法可供调用: pm.environment.has(variableName:String) → boolean pm.environment.get(variableName:String) pm.environment.set(variableName:String, variableValue:String) pm.environment.unset(variableName:String) pm.environment.clear() pm.environment.toObject() pm.variables对象: pm.variables.get(variableName:String) 在使用的时候,要注意变量的优先级,尽量不要在全局变量、环境变量、 集合脚本中出现命名相同的变量。其他脚本介绍pm.request与pm.response :请求与响应信息,打印这两个对象可以看到请求和响应的具体参数之类的。pm.iterationData对象:包含数据集运行期间提供的数据文件pm.cookies对象:cookies的相关信息 pm.response.to.be.* 可以通过预定义的规则直接断言pm.response.to.be.info,检查响应码是否为1××,如果是则断言为真,否则为假。 pm.response.to.be.success,检查响应码是否为2××,如果是则断言为真,否则为假。 pm.response.to.be.redirection,检查响应码是否为3××,如果是则断言为真,否则为假。 pm.response.to.be.clientError,检查响应码是否为4××,如果是则断言为真,否则为假。 pm.response.to.be.serverError,检查响应码是否为5××,如果是则断言为真,否则为假。 pm.response.to.be.error,检查响应码是否为4××或者5××,如果是则断言为真,否则为假。 pm.response.to.be.ok,检查响应码是否为200,如果是则断言为真,否则为假。 pm.response.to.be.accepted,检查响应码是否为202,如果是则断言为真,否则为假。 pm.response.to.be.badRequest,检查响应码是否为400,如果是则断言为真,否则为假。 pm.response.to.be.unauthorized,检查响应码是否为401,如果是则断言为真,否则为假。 pm.response.to.be.forbidden,检查响应码是否为403,如果是则断言为真,否则为假。 pm.response.to.be.notFound,检查响应码是否为404,如果是则断言为真,否则为假。 pm.response.to.be.rateLimited,检查响应码是否为429,如果是则断言为真,否则为假。以上脚本可以直接单独使用某一行就行,运行后直接具备断言的效果,会直接在报告中体现是成功还是断言失败:
当在一个Collections下有多个请求时,在运行的时候,是通过Run的方式去运行请求的,在postman工具页面,可以通过手动拖动去调整脚本执行的顺序,那么在代码中怎么去控制执行顺序呢?可以借助下面的命令实现:设置下一步要执行的请求的命令如下。 Postman.setNextRequest("request_name"); 停止工作流程的执行的命令如下。 Postman.setNextRequest(null);关于Postman.setNextRequest()的一些要点如下。① 指定后续请求的名称或ID,而集合运行器将负责其余部分。② 可以在预请求或测试脚本中使用。一旦设置了多个值,则最后一个生效。③ 如果在请求中没有postman.setNextRequest(),则集合runner默认为线性执行,并移动到下一个请求。因此,要么在集合列表就直接按顺序把请求信息排列好,要么就在请求中写脚本去控制顺序。
前面章节解决了“请求本身”的问题,但“请求前后的动作”是怎样处理的呢?比如在发送一个请求前,需要获取当前时间戳,这就需要用到Pre-request Script的知识了。另外,似乎还忽略了一个非常重要的知识点,请求返回响应后,如何自动判断响应是否正确呢?这就需要用到Tests的知识。本章将重点介绍Pre-request Script和Tests的相关知识。对于单个请求而言,两个脚本执行顺序:Pre-request Script:在发送请求之前执行Tests:在发送请求之后执行站在集合角度,执行顺序如下:① 与集合相关的Pre-request Script脚本将在集合中的每个请求之前运行。② 与文件夹相关联的Pre-request Script脚本将在文件夹中的每个请求之前运行。③ 与集合相关的Tests脚本将在集合中的每个请求之后运行。④ 与文件夹关联的Tests脚本将在该文件夹中的请求之后运行。集合和文件夹也能设置脚本,这点我之前没关注过:因此可以得出结论:集合级脚本>文件夹级脚本>请求级脚本 {优先级从高->低}Pre-request Script脚本的使用场景:一般用来在发送请求之前对数据进行一些预处理,比如获取当前时间戳、随机数之类的用于接口传参。常见的函数以及用法有:pm.environment.get("variable_key"); pm.globals.get("variable_key"); pm.variables.get("variable_key"); pm.collectionVariables.get("variable_key"); pm.environment.set("variable_key", "variable_value"); pm.globals.set("variable_key", "variable_value"); pm.collectionVariables.set("variable_key", "variable_value"); pm.environment.unset("variable_key"); pm.globals.unset("variable_key"); pm.collectionVariables.unset("variable_key"); pm.sendRequest("https://postman-echo.com/get", function (err, response) { console.log(response.json()); });说明:postman中的自己编写的脚本目前一般是只支持用js,但是你可以通过其他的方式去间接的嵌入python脚本, postman在Pre-request Script脚本中是可以发送请求的,那么你可以把写的python或者其他语言的脚本发布为api的接口,然后在postman中以接口的形式去进行调用。Tests脚本使用场景:Postman工具借助测试脚来帮助用户自动判断接口请求是否正确,相当于Load Runner工具中的检查点或者JMeter中的断言功能。列举结果最基础的断言里面常用的函数://检查响应状态是不是200 pm.test("Status code is 200", function () { pm.response.to.have.status(200); }); //检查返回结果会否包含某个字符串 pm.test("Body matches string", function () { pm.expect(pm.response.text()).to.include("string_you_want_to_search"); }); //响应时间会否小于200毫秒 pm.test("Response time is less than 200ms", function () { pm.expect(pm.response.responseTime).to.be.below(200); });官网上,一些脚本的使用案例,感兴趣的可以自己学习:https://learning.postman.com/docs/writing-scripts/script-references/test-examples/英文文档并不可怕,一些简单的英文单词什么的还是应该要能够看懂的。
最近在新公司电脑上搭建python环境的时候,现在python更新到3.9版本了,然后下载下来之后,配好环境变量,然后安装requests插件,然后写一个简单的代码发送请求,结果发现居然报错了:import requests res = requests.get(url="https://blog.csdn.net/liboshi123/", verify=False)运行上面的代码的时候,发现报了下面的错误: raise ValueError("check_hostname requires server_hostname") ValueError: check_hostname requires server_hostname报错的原因:这个其实跟选用的python版本的关系不大,主要原因是因为每次使用 pip install 命令下载插件的时候,下载的都是最新的版本,比如下载requests插件,它会自动的将依赖的urllib3这个插件也安装,然后依赖的插件版本太高,就导致了这个报错的问题。所以说,一般遇到这种莫名其妙的问题的时候,可以先去看一下是不是插件的问题导致的,解决措施就是 将urllib3插件的版本降低就可以,当然,直接在安装requests插件的时候,选择用低版本也可以解决这个问题。比如用下面的命令指定版本进行安装:pip install requests==2.20 或者使用下面的命令降低版本: pip install urllib3==1.25.8这种类似的问题,在使用一些框架的时候经常会遇到,比如有的小伙伴在学习django,然后照着别人博客写的文章操作,最后报错,很有可能就是插件的版本导致的。另外,在线安装插件时,如果插件下载过慢,或者报错的话,可以在插件的命令后面加上 -i 指定插件安装的源。pip install 插件名称 -i http://mirrors.aliyun.com/pypi/simple有时候报插件找不到的话,就换一个源试试。不想每次都指定源进行安装的话 ,那就在用户名下文件夹下建一个pip的文件夹,然后新建pip.ini的配置文件,写入下面的内容就行(具体的源可以自己选择):{创建这个配置文件的存放位置有很多种方式都可以,感兴趣的可以自己去试试,比如pip所在目录下,或者%APPDATA%目录下去新建文件夹。}[global] index-url = http://mirrors.aliyun.com/pypi/simple [install] trusted-host=mirrors.aliyun.com另外,有些插件通过上面的在线方式就是容易出现报错的,可以尝试用离线安装的方式去安装插件,去网上下载whl格式的文件进行安装,比如,可以在下面的链接下下载:whl格式插件:https://www.lfd.uci.edu/~gohlke/pythonlibs/#lxmlpip install xxx.whl官网下载插件:https://pypi.org/解压后,在目录执行:python setup.py install
今天介绍一种新的数据类型-哈希,也有的地方叫散列。这种数据格式在工作中还挺常见的,哈希有点类似于编程里面的对象的概念,可以在一个对象里面去定义多组键值对,这多个键值对相当于打包绑定在了一起。 在常见的GUI客户端下面查看哈希的数据显示格式:哈希常见的操作命令:{key和value只能是字符串类型,不支持再嵌套其他格式数据}HSET 为字段设置值格式:hset key field value [field value ...] 向名称为 key 的 hash 中添加元素hset user:libo name libo age 29 phone 13522223033 email 11111@qq.com hset user:001 name lico age 231、key采用统一的前缀,然后用:区分时,显示的效果会按照前缀进行分组展示2、使用hset对哈希中单个已存在字段进行覆盖更新时,返回0。 HSETNX:只在字段不存在的情况下为它设置值格式:HSETNX hash field valueHGET:获取字段的值格式:hget hash fieldHINCRBY:对字段存储的整数值执行加法或者减法的操作格式:hincrby key field increment只能针对整数值进行操作,否则会报错:HINCRBYFLOAT:对字段存储的数字值(整数/小数都可以)进行浮点数的加减法操作格式:hincrbyfloat key field incrementHSTRLEN:获取字段值的字节长度格式:hstrlen key fieldHEXISTS:检查字段是否存在格式:hexists key fieldhexists user nameHDEL:删除字段格式:hdel key field (可以传多个字段,用空格隔开)hdel user name hdel user name1 name2HLEN:获取哈希包含的字段数量格式:hlen keyhlen userHMSET:一次性为一个/多个字段设置值格式:hmset key field value [field value ...]hmset user name libo age 29 phone 17665****50 HMGET:一次获取一个/多个值格式:hmget key field [field...]HKEYS:获取所有字段格式:hkeys keyhkey userHVALS:获取所有值格式:hvals keyHGETALL:获取所有字段和值格式:hgetall keyhgetall userHASH的一些使用场景:1、购物车的设计以用户id为key,商品id为field,商品数量为value,恰好构成了购物车的3个要素哈希这个类型在工作中存储数据经常用到,一些常用的命令要了解一下,避免在工作中用错了。
为什么突然间要写搭建MonoDB的教程呢,因为公司有需要用到呀。目前所在的公司,有部分数据是存储在MongoDB中的,而且目前今后的工作可能会偏向于验证数据,因此需要掌握对这个数据库的一些基本用法,怕有些操作到时候不敢直接在公司数据库上进行操作,先在自己服务器上学习一下基本的用法。老套路,这里推荐使用docker的方式来搭建这样一个数据库,具体操作如下:1、下载最新镜像:docker pull mongo:latest2、启动镜像在服务器创建一个目录 用来存储数据做数据持久化 mkdir -p /root/docker_volume/mongodb/data docker run -itd --name mongodb -v /root/docker_volume/mongodb/data:/data/db -p 12345:27017 mongo --auth 参数说明: -p 27017:27017 :映射容器服务的 27017 端口到宿主机的 12345(可自己改,这里改成不一致的,避免遭到黑客攻击) 端口。外部可以直接通过 宿主机 ip:12345访问到 mongo 的服务。 --auth:需要密码才能访问容器服务,启动容器后进入容器为用户设置密码3、创建一个名为 admin,密码为 123456 的用户docker exec -it mongodb mongo admin 创建一个名为 admin,密码为 123456 的用户。 > db.createUser({ user:'admin',pwd:'123456',roles:[ { role:'userAdminAnyDatabase', db: 'admin'},"readWriteAnyDatabase"]}); # 尝试使用上面创建的用户信息进行连接。 > db.auth('admin', '123456')4、通过navicat工具(非开源)连接mongodb数据库5、如果公司不允许使用破解软件的,可以考虑使用Robo 3T (免费开源)这个软件去连接MongoDB (https://robomongo.org/):连接后页面如下:
从之前的文章中,介绍了如何在自己的linux服务器上安装redis,接下来介绍一款目前在用的Redis的GUI客户端工具,它就是Another Redis Desktop Manager。好处就是免费(就冲国内很多人喜欢白嫖这一点) ,因为公司不允许使用破解软件。Another Redis Desktop Manager下载地址:https://github.com/qishibo/AnotherRedisDesktopManager/releaseswindows、mac、linux电脑上均可使用,具体操作如下:1、安装后,打开软件 :2、点击New Connection(新建连接),输入相关信息进行连接即可3、GUI工具的一些其他操作查看redis的版本:切换命令行模式:一些其他操作:设置页面截图:GUI工具的操作很简单,另外也有一些其他的GUI工具可以选择,不过有的可能要收费。其他的GUI工具下载地址RedisStudio 下载地址:https://github.com/cinience/RedisStudio/releasesRedisClient 下载地址:https://github.com/caoxinyu/RedisClient/releasesRedis Desktop Manager下载地址(官网下载已经显示个人版都要收费了) :https://github.com/uglide/RedisDesktopManager/releases
上篇文章中,已经介绍了Redis是什么,以及如何使用docker在服务器上安装redis,接下来看一下字符串在redis中是如何进行相关操作的。先在服务器上用命令行连接上redis服务:docker exec -it redis bash redis-cli -h 127.0.0.1 -p 6379说明:一般redis默认的端口都是6379,-h可以理解为host的缩写,-p可以理解为端口port的缩写,这样比较容易记住命令,也可以输入redis-cli --help去查看命令的可选参数的含义。 Redis中针对字符串的基本操作SET 为字符串键设置值语法:set key value可选参数 NX | XXNX:只有在指定的键没有值的时候才会去设置XX:对已有的值进行覆盖更新的时候用XX,如果key不存在,用这个会返回nil,gui工具上的命令行操作可能返回null。目前的版本不加参数默认是会覆盖更新,不确定以后是否会更改。set name libo set wx xiaobotester set name zhangsan NX --name已经指定值,无法更新,会返回nil set name zhangsan XX --会将name的值更新 set a 123 XX -- 如果不存在key为a的数据,则这样使用会返回a 以上的nx和xx我在命令行试了不区分大小写GET:获取字符串键的值语法:get key如果给定的key值在数据库中没匹配到对应的数据,就会返回空get name get phoneGETSET:获取旧值并设置新值首先获取字符串键目前已有的值,接着为键设置新值,最后把之前获取到的旧值返回给用户。如果key本身不存在,则会创建key,然后写入新的值。127.0.0.1:6379> get a "4" 127.0.0.1:6379> getset a 1 "4" 127.0.0.1:6379> get a "1" 127.0.0.1:6379> get f (nil) 127.0.0.1:6379> getset f 1 (nil) 127.0.0.1:6379> get f "1"MSET:一次为多个字符串键设置值语法:mset key1 value1 key2 value2 ... 127.0.0.1:6379> mset name libo age 29 email none@qq.com OK 127.0.0.1:6379> mget name age email 1) "libo" 2) "29" 3) "none@qq.com" 127.0.0.1:6379> MSETNX:只在键不存在的情况下,一次为多个字符串键设置值语法:msetnx key1 value1 key2 value2 ...MSETNX与MSET的主要区别在于,MSETNX只会在所有给定键都不存在的情况下对键进行设置,而不会像MSET那样直接覆盖键已有的值:如果在给定键当中,即使有一个键已经有值了,那么MSETNX命令也会放弃对所有给定键的设置操作。MSETNX命令在成功执行设置操作时返回1,在放弃执行设置操作时则返回0。STRLEN:获取字符串值的字节长度 语法:STRLEN keyAPPEND:追加新内容到值的末尾语法:append key valueAPPEND命令在执行追加操作之后,会返回字符串值当前的长度作为命令的返回值。 Redis中针对字符串以索引的方式进行操作字符串值的正数索引以0为开始,从字符串的开头向结尾不断递增。字符串值的负数索引以-1为开始,从字符串的结尾向开头不断递减。GETRANGE:获取字符串值指定索引范围上的内容getrange key start end127.0.0.1:6379> set str abcdefghijklmnopqrstuvwxyz OK 127.0.0.1:6379> getrange str 0 6 "abcdefg" 127.0.0.1:6379> getrange str -7 -1 "tuvwxyz"SETRANGE:对字符串值的指定索引范围进行设置语法:setrange key index string将字符串键的值从索引index开始的部分替换为指定的新内容,被替换内容的长度取决于新内容的长度,命令执行完之后,会返回字符串值当前的长度作为结果。127.0.0.1:6379> get str "abcdefghijklmnopqrstuvwxyz" 127.0.0.1:6379> setrange str 7 17665367850 (integer) 26 127.0.0.1:6379> get str "abcdefg17665367850stuvwxyz"当输入的索引值比字符串的总长度大,或者说替换之后的新内容的长度超过原来字符串长度的时候,会自动扩展长度保证值可以写入。 写在最后那作为测试人员,学redis的这些基本操作到底有没有用呢? 答案当然是有用的。有些数据可能是存在redis的,当你想快速验证某个场景,找数据比较麻烦的时候,除了用mock,就可以自己去改redis里面的数据,验证页面显示的效果是否同步发生变化。那一般用命令行操作还是GUI工具去操作比较好呢? 建议先熟悉一下命令行的操作,再考虑用GUI的工具,毕竟GUI工具打开占用的内存什么的要多一些,而且有的服务可能不能直连,在登录服务器后,用命令行操作会方便一点。这么多的命令,需要一个个去记吗? 不需要全部记住这么多命令,但是最起码要知道通过命令行可以做一些什么事情,要知道个大概,其实这些命令也比较好记,一般set和get是配套使用的,一个用来设置值,一个用来取值,前缀加m表示可批量操作,剩下的一些命令在用的时候查查资料也行,前提是要知道可以用来干什么事情,在需要的才知道在自己购买的阿里云或者腾讯云之类的服务器上搭建redis的时候,要记得在安全组里面开启端口防火墙,而且数据库记得要设置密码,否则就会出现像下面的情况:(之前没有设置密码,也没有改默认端口,可能被人攻击了)针对这个情况,我更改了一下docker启动redis的命令:docker run -itd --name redis -p 映射到服务器对外暴露的端口:6379 -v /root/docker_volume/redis/data:/data redis --requirepass 这里填入为数据库设置的密码 --appendonly yes 1、加入了映射数据卷,以及数据持久化的参数,可以把数据映射到服务器的目录,至于为什么要加这些参数,有什么好处,可以自己思考/百度一下2、设置了密码,没这么容易被破解,容器内部的话还是用6379端口去连接就行:redis-cli -h 127.0.0.1 -p 6379 -a 密码
Redis介绍 大家或许会有这样的疑问,作为一个测试人员,去专门学这个干什么呢?理由很简单,工作中要用到啊,现在很多公司都会用到redis,自己搭建环境的时候,可能也会涉及到要搭建redis环境,那redis到底能为我们做什么呢? 用作数据库、缓存以及消息代理等Redis到底是什么呢? Redis是一种开源的key-value格式存储系统,是跨平台的非关系型数据库,是主流的nosql中的一种。Redis因其丰富的数据结构、极快的速度、齐全的功能而为人所知,在互联网上有非常广泛的应用。 Redis为用户提供了字符串、散列、列表、集合、有序集合、HyperLogLog、位图、流、地理坐标等一系列丰富的数据结构,每种数据结构都适用于解决特定的问题。在有需要的时候,用户还可以通过事务、Lua脚本、模块等特性,扩展已有数据结构的功能,甚至从零实现自己专属的数据结构。通过这些数据结构和特性,Redis能够确保用户可以使用适合的工具去解决问题。我一般学一个数据库之类的,会先在本地搭一个对应的环境用来练习,等熟练了相关操作之后,再去公司的数据库上操作,避免因为自己的操作失误,给别人的工作带来困扰。而且搭建环境相关的,我现在喜欢用优先用Docker去处理。 Redis环境搭建首先要拉取镜像: docker pull redis:latest镜像pull下来之后,就可以执行命令启动容器,然后进行连接docker run -itd --name redis -p 6379:6379 redis 用下面的命令进入容器里面: docker exec -it redis /bin/bash 然后再执行下面的命令连接redis,然后就可以进行相关操作了: redis-cli -h 127.0.0.1 -p 6379以上操作需要在linux系统上进行操作喔,docker的话,也不建议在windows系统上操作,可能会遇到各种未知的问题。也可以使用GUI工具连接redis进行操作,比如Another Redis Desktop Manager或者Redis Desktop Manager。
Postman中变量的使用使用变量的好处:提升脚本的可维护性,维护起来更灵活方便变量的作用域:变量的生效范围以及优先级变量的优先级:当变量重名时, 优先级(由高->低)为:环境变量>Collection变量>全局变量(Globals)注意事项:1、在postman的Pre-request Script中设置全局变量后,会把变量存储到全局变量中,删掉脚本后,变量仍然可以读取,如果用脚本设置全局变量的话,要注意不要在多个脚本中同时去设置相同的变量名,避免引起冲突,出现问题不好排查2、环境变量需要在运行的时候选择对应的环境变量才会生效,不选择就不会从环境变量中获取环境变量维护页面如下图所示:VARIAVLE: 变量名INITIAL VALUE: 共享初始值, 用于团队共享时供别人使用的默认值CURRENT VALUE: 当前值, 自己当前使用的变量值(一般我们只用设置这个值即可)Perisit All: 保持所有, 将当前自己使用的值(CURRENT VALUE)替换所有的初始值Reset All: 重置所有, 将当前所有的CURRENT VALUE重置为与当前初始值一样设置环境变量默认值的时候,要注意不要输入错了位置,一个是给自己调试用的,一个是共享给其他人用的。 Postman中Collections(集合)的使用集合:从字面上的意思,就是把一些请求整理放在一起使用集合的好处:可以把集合当做一个项目去管理,然后在集合下面创建不同的文件夹代表不同的模块,类似PO模式的思想去管理测试用例,也可以按照不同环境去创建文件夹保存用例。tips:1、鼠标移到集合上,点击集合名称后面的收藏图标,可以将对应的集合排序到前面2、集合可以共享给别人,如果通过链接的方式共享,共享的是当时的快照。也可以导出成json文件发给别人,到时候直接导入就行。导出的时候是不包含环境变量的,需要单独再导出环境变量的数据。集合的运行:鼠标选中集合,然后右侧会出现Run的选项点击run按钮之后,页面如下:可以在用例列表用鼠标拖动用例的顺序Iterations :迭代次数Delay :请求间的间隔时间,默认为0也就是没有间隔Data :读取数据文件进行参数化的选项Save responses : 保存响应数据,默认情况不开启,用例太多时影响性能keep variable values : 变量持久化,默认为开启状态,开启后,前面请求的变量设置的值,后面有请求修改此值,会覆盖此值 。Save cookies after collection run : 集合中的请求在执行期间创建/更新cookie 。打开此选项,可以将cookie保存到cookie管理器演示一下Data的用法:支持加载json或者csv文件,新建一个csv文件,内容如下:username,password demo,demo admin,admin admin,admin123456 demo,123456在csv文件中定义了2列,username和password,给了4组数据,在运行集合的时候,选择改csv文件运行即可,有点类似于写代码做自动化的时候的数据驱动。然后点击运行按钮,可以打开postman的console窗口,看到发送请求的信息如下:
Jmeter使用技巧分享通过Fiddler导出jmeter脚本做接口测试的时候,在没有需求文档的情况下,往往会通过抓包去自己分析接口的相关参数,然后在自己手写脚本去实现接口自动化。接下来介绍一个小技巧,通过Fiddler的一个插件,抓包后直接导出成jmx文件(jmeter脚本)。插件为:JmeterExport.dll,下载地址为:链接:https://pan.baidu.com/s/16yAueWXLzSPIPIQBxo2FVA提取码:1234插件使用方法:1、将JmeterExport.dll复制到Fiddler安装目录下的ImportExport文件夹中,然后启动Fiddler进行抓包,然后在请求列表中选择要导出的接口,点击左上角菜单的File->Export Sessions ,然后在弹出框中选择Jmeter Scripts选项,即可导出jmx文件。(在Fiddler5.0的版本上测试过可以使用 ,建议不要使用太低版本尝试)2、将导出的jmx文件用jmeter打开即可。打开的时候可能会报如下错误:这是因为我使用的fiddler插件导出的脚本中添加了json响应断言的插件,需要下载一个jmeter-plugins-json的插件放置在jmeter安装目录lib文件夹下的ext文件夹中即可。对应的插件在上面的网盘地址中有提供。当然,如果大家从网上下载其他版本的fiddler导出插件的话,导出的脚本可能不会报错。使用jmeter-plugins-manager插件在线管理jmeter插件Jmeter提供了一个在线下载和升级插件的插件管理的官方插件,名为jmeter-plugins-manager,下载对应的jar包放置于安装目录下的lib\ext文件夹下即可,然后启动jmeter,在菜单栏选项下面,会多出一个Plugins Manager的菜单:
2022年01月