一、软件测试基础理论
1.软件的定义:数据和指令
2.软件的分类:
1) .场景:工具类、游戏、电商、媒体
2) .架构:
单机版:不需要联网
分布式:需要联网
B/S:浏览器器/服务器
C/S:客户端/服务器
3.软件测试
1.定义:通过人工或者自动化验证实际结果与需求是否一致过程
2.原则
缺陷集群性(28原则)
测试显示软件存在的缺陷
杀虫剂悖(bei)论
测试活动依赖测试内容
没有错误是好谬论
穷尽测试是不可能的
测试尽早介入
4.开发模型
1.瀑布流模型
2.快速原型
3.增量模型
4.敏捷开发
5.测试模型
V模型
W模型
H模型
X模型
6.软件测试流程
|阶段|产物|
|:-:|:-:|:-:|
First Header | Second Header | Third Header |
---|---|---|
阶段 | 工作内容 | 产物 |
准备 | 立项、需求分析、需求评审 | PRD |
计划 | 编写、评审测试计划 | 测试计划 |
设计 | 提取测试点、编写、评审测试用例 | 测试用例 |
执行 | 冒烟测试、执行测试、提bug、回归测试 | 缺陷报告 |
完成 | 验收测试、编写测试报告、项目上线 | 测试报告 |
7.软件测试分类
1.技术:黑白灰
2.阶段:
|阶段|产物|
|:-:|:-:|:-:||:-:|
First Header | Second Header | Third Header | |
---|---|---|---|
阶段 | 测试对象 | 测试人员 | 测试方法 |
单元测试 | 一个模块、类、方法 | 开发/白盒测试工程师 | 白盒测试 |
集成测试 | 一个模块、类、方法组装成一个系统或者子系统 | 开发/白盒测试工程师 | 白盒/黑盒测试 |
系统测试 | 整个软件系统 | 黑盒测试工程师 | 黑盒测试 |
验收测试 | 整个软件系统 | 黑盒测试工程师/用户/老板/经理 | 黑盒测试 |
3.内容
1.功能:UI测试、冒烟、回归测试
2.性能:压力、负载、并发
3.兼容性:
App:Android版本、厂商、屏幕分辨率、屏幕样式(水滴、刘海、全屏、曲面、折叠)
web:浏览器内核、版本
4.专项测试
APP:安装卸载、升级、中断、弱网
二、测试计划
1.模板
1.测试目的:整体概述、详细描述
2.测试资源:人力资源
|:-:|:-:|:-:|
First Header | Second Header | Third Header |
---|---|---|
姓名 | 职务 | 岗位职责 |
硬件
|:-:|:-:|:-:|:-:|
First Header | Second Header | Third Header | |
---|---|---|---|
名称 | 配置 | 数量 | 备注 |
软件资源
First Header | Second Header | Third Header |
---|---|---|
软件名称 | 描述 | |
网络资源
First Header | Second Header | Third Header |
---|---|---|
互联网 | 局域网 | |
3.测试范围:对象、特性、非特性
4.测试风险:人资法环时+具体项目风险
|:-:|:-:|:-:|:-:|:-:|:-:|
| 编号 | 风险描述 | 风险等级 | 责任人 | 影响 | 规避方法 |
| | | | | | |
5.人员分工
| 姓名 | 职务 | 工作内容 |
| | | |
6.测试策略
功能
接口
界面
兼容性
性能
7.测试进度
| 测试任务 | 负责人 | 预开始时间 | 预结束时间 | 进度 | 备注 |
| | | | | | |
8.测试准则
| 阶段 | 启动准则 | 暂停准则 | 在启动准则 | 结束准则 |
| 集成测试 | | | | |
| 系统测试 | | | | |
| 验收测试 | | | | |
9.测试输出
| 名称 | 负责人 | 路径 |
| 测试计划 | | |
| 测试用例 | | |
| 测试报告 | | |
| 缺陷报告 | | |
2.怎么写
1.设计封面:项目名称、标题、版本、表格、组别
2.九大项
3.插入目录
三、测试用例
1.等价类划分法
1.定义:输入数据分为若干个区域,取有代表性的数据
2.分类:
1.有效等价类:合理的数据
2.无效等价类:不合理的数据
2\. 边界值分析法:
定义:取稍高于或稍低于边界的一些数据进行测试,使用离点、上点、内点确定取值。
3\. 获取·:
1.上点:边界点
2.内点边界内部的点
3.离点:开内闭外
4.场景法
定义:模拟实际用户场景
分类:
1.基本流:正确流程
2.备选流:正确的流程每一个步骤取反
5\. 错误推测法:
测试经验丰富的人喜欢使用的一种测试用例设计方法。一般这种方法是基于经验和直觉推测程序中可能发送的各种错误,有针对性地设计。只能作为一种补充。
6\. 因果图方法:
比较适合输入条件比较多的情况,测试所有的输入条件的排列组合。所谓的原因就是输入,所谓的结果就是输出。5\. 场景法:通过模拟业务场景来对系统的功能点或业务流程的描述,从而提高测试效果的黑盒测试方法
7.判定表
8.正交实验法
发红包、朋友圈、水杯、小视频
四、禅道
1.安装:下一步
2.使用
1.测试bug(测试人员):测试到提bug
2.解决bug(开发):测试 到 bug 到 确认 到 完成
3.再次测试(测试人员):测试 到 再次测试 到 如果解决,点击关闭,否则重新编辑
五、postman使用(一)
5.1.1 什么是Postman
Postman 提供功能强大的 Web API 和 HTTP 请求的调试,它能够发送任何类型的HTTP 请求
(GET, POST, PUT, DELETE…),并且能附带任何数量的参数和 Headers。而且它还提供测试数据和环境
配置数据的导入导出,付费的 Post Cloud 用户还能够创建自己的 Team Library 用来团队协作式的测
试,并能够 将自己的测试收藏夹和用例数据分享给团队。
postman适用于不同的操作系统,还支持postman浏览器扩展程序、postman chrome应用程序等。但
是 浏览器插件目前Google已经停止更新了。
5.2 Postman下载和安装
5.2.1 Postman的下载
官网下载: 地址:https://www.getpostman.com/downloads/,选择页面中的“Download”,根据自己电脑配置, 选择32位下载还是64位下载
5.2.2 Postman的安装过程
1、双击下载好的安装包
2、因为Postman是免安装的,双击安装包,自动安装到本地电脑中
3、查看Postman界面,出现如下图所示,说明安装成功
4、登录,点击进入workspace页面
5.3 Postman主界面的介绍
5.3.1 工具栏
5.4 Postman基本操作
5.4.1 新建测试集、文件夹、请求用例
点击collections,点击+,点击create new collection
点击collection右边的三个点,点击add request是添加请求,add folder是添加文件夹
5.4.2 get请求
新建一个get请求,如图所示
1.设置请求方式为get
2.粘贴网址
3.添加请求参数,参数添加后会在url上显示出来,如图中所示的?id=1005008&page=1&size=100
4.如果有请求头,在请求头的部分添加,也是键值对
5.点击send之后,下面显示响应数据,可以是html,json,xml...
5.4.3 post请求
1\. 提交form表单,如图所示
https://www.wanandroid.com/user/login
方法:POST
参数:
username,password
post请求的参数信息在Body中添加
form表单提交需要选中x-www-form-urlencoded
请求头添加和get请求相同,在Headers中添加
need-to-insert-img
need-to-insert-img
2. json提交
下图中,当我们选择JSON(application/json) 是会自动帮我们设置 headers 为 application/json
在这里就不截图 举例了
need-to-insert-img
3. xml提交
need-to-insert-img
4. 二进制文件提交
need-to-insert-img
其它请求方式如PUT,DELETE 大致流程和GET,POST 差不多,这里就不一一举例说明了
5.4.4 授权Authorization
Authorization,授权就是验证我们是否有权限从服务器访问所需的数据。发送请求时,通常必须包含参数以确保请求有权访问并返回所需的数据,比如需要登录之后才能访问的数据。Postman提供的授权类型可以让我们轻松处理Postman进行接口测试中的身份验证协议。
在postman中Authorization分为以下几种类型:
注意:应当注意:NTLM和BearerToken仅在Postman本地应用程序中可用。所有其他授权类型都可以在Postman本地应用程序和Chrome应用程序中使用。
1. Inherit auth from parent
向集合或文件夹添加授权。
假设您在集合中添加了一个文件夹。在授权选项卡下,默认的授权类型将被设置为“从父类继承auth”。
“从父”设置的“继承auth”指示默认情况下,该文件夹中的每个请求都使用父类的授权类型。在本例中,该集合使用“No Auth”,因此该文件夹使用“No Auth”,这意味着该文件夹中的所有请求将使用“No Auth”
如果您希望将父集合授权类型保留为“No Auth”,但要更新这个特定的文件夹的授权助手,该怎么办呢?您可以编辑文件夹的详细信息,从类型下拉菜单中选择“基本的Auth”,并输入您的凭证。因此,这个文件夹中的每个请求都依赖于“基本的Auth”,而父集合中的其余请求仍然不使用任何授权
2. No Auth
默认情况下,“No Auth”出现在下拉菜单列表中。当您不需要授权参数发送请求时,使用“No Auth”。
3. Bearer Token
Bearer Token是安全令牌。任何带有Bearer Token的用户都可以使用它来访问数据资源,而无需使用加密密钥。
使用Bearer Token:
第一步:从下拉菜单中选择“Bearer Token”。
第二步:要设置请求的授权参数,请输入令牌的值。
第三步:点击发送按钮
4. Basic auth
Basic Auth是一种授权类型,需要验证用户名和密码才能访问数据资源。
使用基本身份验证:
第一步:从下拉菜单中选择“Basic Auth”。
第二步:要设置请求的授权参数,请输入您的用户名和密码。
第三步:点击发送按钮。
5. Digest Auth
在“Digest Auth”流程中,客户端向服务器发送请求,服务器返回客户端的nonce和realm值;客户端对用户名、密码、nonce值、HTTP请求方法、被请求资源URI等组合后进行MD5运算,把计算得到的摘要信息发送给服务端。服务器然后发回客户端请求的数据。
通过哈希算法对通信双方身份的认证十分常见,它的好处就是不必把具备密码的信息对外传输,只需将这些密码信息加入一个对方给定的随机值计算哈希值,最后将哈希值传给对方,对方就可以认证你的身份。
Digest思想同样采如此,用了一种nonce随机数字符串,双方约好对哪些信息进行哈希运算即可完成双方身份的验证。Digest模式避免了密码在网络上明文传输,提高了安全性,但它仍然存在缺点,例如认证报文被攻击者拦截到攻击者可以获取到资源。
默认情况下,Postman从响应中提取值对应的值。如果不想提取这些值,有以下两种选择:
在所选字段的高级部分中输入您自己的值勾选“Yes,disable retrying the request”复选框。
6. OAuth 1.0
OAuth 1.0是一种可以让我们在不公开密码的情况下授权使用其他应用程序的授权模式。
在Postman中按照以下步骤使用OAuth 1.0授权:
在Authorization下来授权标签中选择“OAuth 1.0”授权模式;在“Add authorization datato” 下拉选择框中,选择对应的请求模式。
当选择“Request Body/Request URL”时,Postman将检查请求方法是POST还是PUT,以及请求主体类型是否是x-www-form-urlencoded;如果是这样,Postman将增加授权参数到请求主体。对于所有其他情况,它会向URL添加授权参数。
7. OAuth 2.0
OAuth 2.0作为OAuth 1.0的升级版本。在Postman中按照以下步骤进行使用:
在Authorization下来授权标签中选择“OAuth 2.0”授权模式在“Add authorization data to”下拉选择框中,选择对应的请求模式;
设置请求的授权参数,有以下三个选择:
点击“Get New Access Token”按钮,在弹出的对话框中输入对应的参数;单击“Request Token”按钮获取对应的Token。接下来有了对应的Token后,就可以点击“Send”按钮发送请求了;
在“Access Token”输入框中输入一个Token,或者Token对应的环境变量,然后就可以点击“Send”按钮发送请求了;
在“Available Tokens”下拉框中选择已经存在的Token,然后发送请求。
案例:
/**
* 登录
* https://www.liulongbin.top:8888/api/private/v1/login
* post
* 参数:
* username(admin),password(123456)
*
* 上传图片
* https://www.liulongbin.top:8888/api/private/v1/upload
* post
* 请求头 :authorization : Bearer
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjU wMCwicmlkIjowLCJpYXQiOjE2MTU4NjI
zODksImV4cCI6MTYxNTk0ODc4OX0.Rr- M1MTfVWER3i8KiIIlfP0mW6oHYu05Sz6WzCeaKSA
* 参数: file -- 文件
*/
可以给接口集
9.5 Pre-request Script--预处理脚本
Pre-request Script,翻译中文为预处理脚本,是请求发送之前需要执行的代码片段,在我们点击send发起请求之前,改区域的代码先执行。
使用场景:例如请求中包含一个随机数或者时间戳(时间的毫秒值),或者参数需要加密。
1\. 给一个接口添加预处理脚本:新建一个网络请求,点击Pre-request Script,写入js脚本获取时间的毫秒值(时间戳)
2.给接口集添加预处理脚本:如图所示,完成后以后接口集下面所有接口在请求的时候都会先执行预请求脚本
在输入框右侧有一些简单的js脚本生成按钮,可以通过按钮生成
5.6 Tests内置脚本
既然有在请求发起之前执行的脚本,那么是否有在请求完成之后执行的脚本呢? 有Tests里面输入的脚本就是在网络请求之后执行的,Postman的强大之处在于其允许在对某一个request访问的之前和之后分别运行自定义的一段Javascript脚本,这样直接就完成了一个chain request的效果,可以将数条request连结成一个流程完成一体化测试。
如下在Pre-request Script和Tests中分别输入了js代码,执行如下如所示:
5.7 命令行运行接口结合
9.7.1 命令行运行
执行命令行前提条件是需要newman,newman是需要nodejs来安装的,所以得先下载安装node.node下载地址:https://nodejs.org/en/download/
cmd模式下输入node -v,回车,显示node版本号,即为安装成功
npm(node package manager):nodejs的包管理器,用于node插件管理(包括安装、卸载、管理依赖等)
cnpm:淘宝团队的cnpm是npm在国内的镜像,可以用此代替官方版本(只读),同步频率目前为 10分钟 一次以保证尽量与官方服务同步。
安装完后查看版本cnpm -v
安装newman:cnpm install newman --global
检查是否安装成功:newman -v
安装newman-reporter-html
执行cnpm install -g newman-reporter-html
在测试文件夹 pmtest 里面可以看到生成的一个 newman 文件夹,打开就可以看到生成的测试报告。
5.8 环境变量的使用
5.8.1 Postman 环境变量的应用
点击眼睛图标可以查看所有的环境变量和全局变量。点击眼睛图标右边的设置图标可以设置环境变量和全局变量。
环境变量可以分组设置,并且在使用的时候选择其中一组环境变量。 使用环境变量 {{baseUrl}} 两边各量个花括号括起来 这个环境变量可以在url 中使用,也可以在header 中能使用,还能在请求体中使用
选中No Environment(选中已有环境就变成编辑了)--> 点击眼睛-->点击Add
案例:新建两个环境,都创建相同的环境变量baseUrl值使用不同的网址,新建请求,使用{{baseUrl}},切换环境后,同一个请求访问到的页面不一样
5.9 全局变量的使用
5.9.1 Postman全局变量的应用
postman 的环境变量可以分组,但是全局变量不能分组,只能有一组全局变量,在设置和使用都类似于环境 变量。在下图位置设置全局变量。
点击右上角眼睛 --> 点击Globals右边的Edit,添加全局变量,点击save保存,和环境变量一样,通过{{timestamp}}引用
案例:添加时间戳
六、缺陷报告
1.1定义
标识并描述发现的缺陷,具有清晰、完整和可重现问题所需的信息的文档。
1.2 什么是缺陷
软件缺陷就是通常说的Bug,它是指在软件中(包括文档和程序)存在的影响软件正常运行的问题。
软件未达到产品说明书标明的功能,如一个即时通讯App不能聊天。
软件出现了产品说明书指明不会出现的错误,如高考不带身份证。
软件功能超出产品说明书指明的范围,如即时通讯App做了一个地图功能。
1.3 软件缺陷产生的原因
需求不明确和变更
软件需求不清晰或者开发人员对需求理解偏差,导致软件设计时偏离用户的需求目标,造成软件功能或特征上的缺陷。此外,开发过程中客户频繁更新需求也会影响软件最终的质量。
软件结构复杂
编码问题
项目期限短
使用新技术
1.4 导致软件缺陷的典型错误
错误软件缺陷
客户与软件开发人员之间交流困难缺少预期的软件功能
开发人员未注意到代码中的逻辑错误单击按钮没有进行任何操作
开发人员忘记了对文件复制代码进行错误检查复制了一份被破坏的文件,导致软件崩溃
开发人员没有理解客户的情况软件不能满足客户的要求
软件缺陷分类
1.6 缺陷报告的核心要素
八项:缺陷编号、缺陷状态、缺陷标题、重现步骤、严重程度、优先级、缺陷类型、测试环境。
缺陷编号
缺陷的唯一标识符
缺陷状态
新建:刚发现的缺陷
已指派:已经由测试人员将缺陷指派给开发人员进行处理
已打开:开发人员正在修复缺陷
已修复:开发人员完成缺陷修复,还未进行回归测试
已拒绝:发开人员拒绝修复
已延期:对缺陷进行延缓处理
已关闭:由测试人员回归测试后,缺陷不存在了
重新打开:由测试人员回归测试后,发现缺陷任然存在,
缺陷标题
缺陷的概述,描述问题本质
重现步骤
①一步一步描述再现缺陷的操作步骤
②预期结果
③实际结果
严重程度
缺陷对软件系统的影响程度
优先级
修复缺陷的重要性或紧迫性
缺陷类型
根据缺陷产生的来源和根源划分出的缺陷种类
功能、配置、安装、性能缺陷
测试环境
测试环境配置,包括软件环境和硬件环境
缺陷报告模板
七、测试报告
1.概述
1.编写目的:背景、内容
2.人员分工
3.测试环境
2.测试过程
1.测试进度
2.用例情况
3.bug统计
3.缺陷分析
1.级别:严重、一般、次要、轻微
2.模块:
解析:bug共21条,其中17条存在于登录/注册模块,开发人员需要着重对于该模块进行自测。
3.版本
4.趋势
5.轮次
6.缺陷总数
4.测试总结
1、测试结论
内容:通过/不通过,执行率、通过率、修复率、遗留问题的级别以及数量。
示例:积云商城1.1测试通过,可以上线。测试用例执行率100%,测试用例通过率95%,未通过的测试用例不影响业务运行。严重缺陷为0,一般缺陷为0,轻微缺陷小于10%。
2、 风险分析
编号 风险描述 规避方法及建议
3、 遗留问题
编号 缺陷描述 缺陷等级 处理方法
八、接口测试
1.网络基础
1.网络模型
1.OSI:物理层、链路层、网络层、传输层、会话层、表示层、应用层。
2.TCP/IP:网络接口层、网际层、运输层、应用层。
3.五层体系:应用层、运输层、网络层、链路、物理层
2.http和http协议
http是网络传输,http协议是客户端到服务器之间的交互
3.http与https区别
4.请求方式:post和get区别
5.状态码:200 300 404 500
6.网络三要素:IP、协议、端口
7.http请求与相应的组合:请求行、消息报头、空行、请求正文 (也叫请求体)
2.接口与接口文档
1.接口:定义、表现形式(协议+主机地址+路径+参数)
2.接口文档:word、showdoc
3.接口测试工具
商业:Loadrunner、SoapUI
2.开源:Jmeter、postman
4.接口测试内容
1.单一接口
2.组合接口
3.返回数据的结构和字段
5接口测试用例.(9+7+3)
9:用例编号、所属模块、用例标题、优先级、前置条件、操作步骤、测试数据、预期结果、实际结果
7:是否通过、bugID、编写人员、编写时间、测试人员、测试时间、备注
3:请求类型、请求参数、类型
九 Charles
9.1 概念:
抓包是将网络传输发送与接收的数据包进行截获、重发、编辑、转存等操作,也用来检查网络安全等。
9.2 常见的抓包工具
Charles、fiddler、wireShark
9.3 Charles简介
9.3.1 什么是Charles
Charles中文名字青花瓷,是一款Http代理服务器和Http监视器,当移动端在无线网连接中按要求设置好代理服务器,使所有对网络的请求都经过Charles客户端来转发时,Charles可以监控这个客户端各个程序所有连接互联网的Http通信。
特点:跨平台、半免费
免费版本:一是启动等待十秒才能启动,二是半小时重启一次
9.3.2 Charles工作原理
9.3.2.1 原理
截获真实客户端的HTTPS请求,伪装客户端向真实服务端发送HTTPS请求
接受真实服务器响应,用Charles自己的证书伪装服务端向真实客户端发送数据内容
9.3.2.2 原理图
9.3.2.3 原理案例
租房子 房客 中介 房东
前置步骤:
(1)需要运行Charles并配置代理
(2)在客户端上面需要配置代理
步骤:
(1)有客户端发送请求
(2)Charles接受再发送给服务端
(3)服务端返回请求结果给Charles
(4)由Charles转发给客户端
9.3.2.4 Charles主要功能
支持HTTP/HTTPS代理
支持流量控制
支持接口并发请求
支持重发网络请求,方便后端调试
支持断点调试
支持修改网络请求参数
支持网络请求的截获并动态修改
支持模拟慢速网络
9.3.2.5 Charles优点(相对Fiddler)
Charles能够支持Linux、macOS,fiddler不支持
Charles支持按域名和按接口查看报文,简洁明了
Charles支持反向代理,fiddler不支持
Charles网络限速可选择网络类型,选择3G、4G、5G等
Charles可以解析AMF协议,一般用不到
十、MySQL
10.1 常见的数据库
MySQL、Oracle、MongoDe、SQLServier、Redis、Sqlite
10.2 数据库和SQL语句关系
数据库是存放数据的,SQL语句是操作数据的
10.3 MySQL 安装以及配置步骤:
10.3.1 下载
10.3.2 安装
10.3.3 配置
10.3.4 卸载:关闭服务、卸载、安装路径全部删除 ( my/in )、删除c/programdata/mysql
10.4 SQL语句
10.4.1 database defination language 数据库定义语言,用于定义数据库,用于定义表结构(简称 DDL)
10.4.1.1 库
查看数据库
show databases
//创建第一个数据库
mydb1create database mydb1
//删除创建的数据库
drop database mydb1;
//选择数据库
user mydb1
查看数据库创建细节
show create database mydb1
创建一个使用gbk字符集的数据库
create database mydb2 character set gbk
10.4.1.2 表
//创建表 create table student(id int,name varchar(20),sex varchar(20),age int,salery float(6,2),birthday date , 类型 字段名)
//删除表
drop table student;
//查看所有表
show tables
//查看表的创建细节
show create table student;
//展示表结构
desc student
// 在原有的学生基础上添加address列
alter table student add address varchar(20)
//在原有的学生基础上删除
address列alter table student drop address
//添加列 字 段
alter table 表名 add 字段名 类型
//删除列 字段
alter table 表名 drop字段名 类型
//表格 约束条件
主键:primary key
自增:auto_increment
非空:not null
唯一:unique
10.4.2 概念 DML : data manipulation language 数据库操作语言,用以操作数据库。
10.4.2.1 插入数据
//插入数据 insert into student values
(1,’zhangsan’,’nan’,19,389.10,’1999-10-10’);
//查询select * from student
10.4.2.2 删除数据
//删除单条数据
delete from student where id=1;
//删除所有数据,不删除结构,会放到日志中,事务提交后才生效 delete from student;
//摧毁表,删除表中所有数据,不删除结构,立即生效
truncate table student;
10.4.2.3 修改数据
//设置所有人的年龄加10岁
update student set age=age+10
//修改 zhangsan 为张三update student set name=’张三’where name=’zhangsan’
//修改王五的salery和出生日期update student set salery=100.01,birthday=’1999-10-10’where id=3;
数据查询
//删除
student drop table student
//创建数据库表-学生成绩表
create table student(id int primary key auto_increment,name varchar(20) unique not null,chinese float,english float,math float);
//添加几条数据
insert into student values(1,’张三’,90,80,80);
insert into student values(2,’李四’,90,87,60);
insert into student values(3,’王五’,70,60,69);
insert into student values(4,’赵六’,99,90,87);
//查询所有学生信息
select*from student;
//查询id为1的学生信息
select*from student where id=1;
//查询id为1的学生姓名
select name from studen twhere id=1;
//查询数学成绩大于80的同学成绩 select*from student where math>80
//查询所有学生成绩,并输出效果为 姓名 语文 英语 数学 效果,见下图:select name as姓名,chinese as语文,english as英语,math as 数学 from student
//查询所有成绩及数学分+10分select*,(math+10)fromstudent//统计每个学生的总分select name,(math+english+chinese)as总分from student
//查询总分大于230分的同学select*from student where(math+english+chinese)>230
//查询数学成绩在80-90之间的同学select*from student where math between 80 and 90
//查询数学语文英语都大于80的同学成绩select*from student where math>80 and english >80 and chinese >80;
//查询数学成绩在 80 60 90内的同学,即数学成绩有60、80、90的。select*from student where math in(80,60,90);
//模糊查询// _ 代表一个,%代表多个(0 - 无限)//查询所有姓名中包含张的同学
select*from student where name like ‘%张%’
排序查询
//按照数学成绩从小到大查询
select*from student order by math;
//按照数学成绩从大到小查询
select*from student order by math desc;
分页查询
//取出第3条至第6条,4条记录
select*from student limit 2,4
//查询出数学成绩由高到低前两名
select*from student order by math desc limit 0,2;
分组查询
//创建一个订单表create table employee(id int,name varchar(20),sex varchar(20),age int);
insert into employee values(1,'sunsan','男',18);
insert into employee values(2,'lisi','男',18);
insert into employee values(3,'wangwu','女',19);
insert into employee values(4,'zhaoliu','男',15);
//分组查询
select * from employee group by sex;
//分组查询加条件
select * from employee group by sex having age>18;
报表查询
count 个数
sum 总数
avg 平均数
max 最大值
min 最小值
//统计班级里边有多少学生
select count(*)from student;
//统计总成绩大于250分的人数select count(*)from student where(math+english+chinese)>250;
//统计班级里边各科总成绩select sum(math),sum(english),sum(chinese)from student
//统计所有科目的总成绩select sum(math+english+chinese)from student;
//统计一下语文平均成绩select sum(chinese)/count(*)from student;select avg(chinese)from student;
//统计一下班级语文最高分和最低分select max(chinese)from student;select min(chinese)from student;//报表查询订单根据名称合并后,总价格>10000的商品select*from orders group by product having sum(price)>7000
数据控制语言
数据控制语言:简称【DCL】(Data Control Language),用来定义数据库的访问权限和安全级别,及创建用户;关键字:grant等
多表设计
十一、Linux常用命令及使用
文件和目录
cd /home 进入 '/ home' 目录'
cd .. 返回上一级目录
cd ../.. 返回上两级目录
cd 进入个人的主目录
cd ~user1 进入个人的主目录
cd - 返回上次所在的目录
pwd 显示工作路径
ls 查看目录中的文件
ls -F 查看目录中的文件
ls -l 显示文件和目录的详细资料
ls -a 显示隐藏文件
ls [0-9] 显示包含数字的文件名和目录名
tree 显示文件和目录由根目录开始的树形结构
lstree 显示文件和目录由根目录开始的树形结构
mkdir dir1 创建一个叫做 'dir1' 的目录'
mkdir dir1 dir2 同时创建两个目录
mkdir -p /tmp/dir1/dir2 创建一个目录树
rm -f file1 删除一个叫做 'file1' 的文件'
rmdir dir1 删除一个叫做 'dir1' 的目录'
rm -rf dir1 删除一个叫做 'dir1' 的目录并同时删除其内容
rm -rf dir1 dir2 同时删除两个目录及它们的内容
mv dir1 new_dir 重命名/移动 一个目录
cp file1 file2 复制一个文件
cp dir/* . 复制一个目录下的所有文件到当前工作目录
cp -a /tmp/dir1 . 复制一个目录到当前工作目录
cp -a dir1 dir2 复制一个目录
cp -r dir1 dir2 复制一个目录及子目录
ln -s file1 lnk1 创建一个指向文件或目录的软链接
ln file1 lnk1 创建一个指向文件或目录的物理链接
touch -t 0712250000 file1 修改一个文件或目录的时间戳 - (YYMMDDhhmm)
file file1 outputs the mime type of the file as text
iconv -l 列出已知的编码
iconv -f fromEncoding -t toEncoding inputFile > outputFile creates a new from the given input file by assuming it is encoded in fromEncoding and converting it to toEncoding.
find . -maxdepth 1 -name *.jpg -print -exec convert "{}" -resize 80x60 "thumbs/{}" ; batch resize files in the current directory and send them to a thumbnails directory (requires convert from Imagemagick)
文件搜索
find / -name file1 从 '/' 开始进入根文件系统搜索文件和目录
find / -user user1 搜索属于用户 'user1' 的文件和目录
find /home/user1 -name *.bin 在目录 '/ home/user1' 中搜索带有'.bin' 结尾的文件
find /usr/bin -type f -atime +100 搜索在过去100天内未被使用过的执行文件
find /usr/bin -type f -mtime -10 搜索在10天内被创建或者修改过的文件
find / -name *.rpm -exec chmod 755 '{}' ; 搜索以 '.rpm' 结尾的文件并定义其权限
find / -xdev -name *.rpm 搜索以 '.rpm' 结尾的文件,忽略光驱、捷盘等可移动设备
locate *.ps 寻找以 '.ps' 结尾的文件 - 先运行 'updatedb' 命令
whereis halt 显示一个二进制文件、源码或man的位置
which halt 显示一个二进制文件或可执行文件的完整路径
**打包和压缩文件 **
tar -xvf a.tar.gz tar -zcvf a.tar.gz aaa.txt
十二、Shell脚本
1、什么是shell脚本
Shell脚本与Windows/Dos下的批处理相似,也就是用各类命令预先放入到一个文件中,方便一次性执行的一个程序文件,主要是方便管理员进行设置或者管理用的。但是它比Windows下的批处理更强大,比用其他编程程序编辑的程序效率更高,它使用了Linux/Unix下的命令。
二、Shell脚本的规则
1、变量的规则
定义变量规则:
变量名=值
shell定义变量的规则:
1: 等号两边不能有空格
2:定义特殊的变量需要用单引号或者双引号结合
3:定义linux命令需要用反单引号
区分单引号和双引号的不同和相同点
双引号中有$变量名,输出的是变量名对应的变量值
单引号中有$变量名,输出的是$变量名
2、脚本的命名格式
脚本名称使用.sh结尾
3、脚本的起始行格式
第一行必须写# !/bin/bash
计算当前文件夹有几个文件
计算任意个一个文件下含有几个文件
脚本输入输出格式
1:输入语句用:read -p "描述"
2:Shell输出值:echo $变量名
脚本的调用
方式1:./脚本名.sh(权限的问题)
方式2: sh 脚本名.sh
注意点:read可以传递多个数据 read –p”name and passwoed”name password
超过的部分都填充在最后一个变量上
参数传递
参数传递 :向.sh文件中传递数据
格式: sh 脚本名.sh 参数
$1:接收第一个参数~~$n
$n: 文件名称
$@: 所有参数 s
$#: 参数个数 $0
比较运算符和逻辑运算符
(1)比较运算符(数字)
-eq 比较是否相等 equal
-ne 比较不相等 not equal
-gt 比较大于 greater than
-ge 比较大于等于 greater equal
-lt 比较小于 less than
-le 比较小于等于 less equal
(2)比较运算符(字符串)
== 比较是否相等
!= 比较不相等
加一操作:((i++)) ((i+=1))
加n操作:s=s+[i] ((s=i))
(3)逻辑运算符
-a 逻辑与 -o逻辑或 !逻辑非
and or
十二、Shell脚本
12.1Shell介绍
Shell脚本与Windows/Dos下的批处理相似,也就是用各类命令预先放入到一个文件中,方便一次性执行的一个程序文件,主要是方便管理员进行设置或者管理用的。但是它比Windows下的批处理更强大,比用其他编程程序编辑的程序效率更高,它使用了Linux/Unix下的命令。
12.2 Shell脚本的规则
Shell 和python都是弱语言
12.2.1、变量的规则
定义变量规则:
变量名=值
shell定义变量的规则:
1: 等号两边不能有空格
2:定义特殊的变量需要用单引号或者双引号结合
3:定义linux命令需要用反单引号
区分单引号和双引号的不同和相同
双引号中有$变量名,输出的是变量名对应的变量值
单引号中有$变量名,输出的是$变量名
脚本的命名格式
脚本名称使用.sh结尾
脚本的起始行格式
第一行必须写# !/bin/bash
脚本输入输出格式
1:输入语句用:read -p "描述"
2:Shell输出值:echo $变量名
5、 脚本的调用
方式1:./脚本名.sh(权限的问题)
方式2: sh 脚本名.sh
注意点:read可以传递多个数据 read –p”name and passwoed”name password
超过的部分都填充在最后一个变量上
参数传递
参数传递 :向.sh文件中传递数据
格式: sh 脚本名.sh 参数
n
@: 所有参数 s
0
![image.png](https://upload-images.jianshu.io/upload_images/26583388-c3137ec38fa302bd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
比较运算符和逻辑运算符
(1)比较运算符(数字)
-eq 比较是否相等 equal
-ne 比较不相等 not equal
-gt 比较大于 greater than
-ge 比较大于等于 greater equal
-lt 比较小于 less than
-le 比较小于等于 less equal
(2)比较运算符(字符串)
== 比较是否相等
!= 比较不相等
加一操作:((i++)) ((i+=1))
加n操作:s=$(($s+$i)) s=$[$s+$i] ((s=$s+$i))
逻辑运算符
-a 逻辑与 -o逻辑或 !逻辑非
and or
if语句
单条件语句格式:
if [ 条件 ]
then
语句
else
语句
fi
多条件语句格式;
if [ 条件 ]
then
语句
elif [ 条件 ]
then
语句
......
else
语句
fi
case规则
格式:
case $变量名 in
"值")
语句;;
"值")
语句;;
.....
esac
注意:
1:case这第一行以in结尾
2:值可以是字符串也可以是数字, 如果数字范围[0-9]
3:结束语句;;
4:esac结束标志
For循环
格式:
for 变量 in 列表
do
语句
done
for i in 1 2 3 4 5
do
echo $i
done
While循环
while [条 件 ]
do
语句
done
注意:
1: while后面有空格, 2:条件两边有空格, 3:while条件里面存在变量,需要$,而且变量两边需要双引号, 4:done是结束标识
Shell脚本的函数
1:定义格式
函数名(){代码 }
调用格式
函数名
注意点:必须先定义一个函数,然后再调用它
2:函数中的参数
使用$n来接收数据
十三、Jmeter
- 性能测试
- 性能测试工具
- jmeter
- Loadrunner
- ab
- Jmeter概述
- JDK环境变量配置
- 安装 → 配置环境变量
- 拷贝 → 配置环境变量
- Jmeter下载、安装:解压使用
- 启动:Linux、Windows
- JDK环境变量配置
- Jmeter使用
- 概念:
- 进程
- 线程组
- 线程
- 基本使用
- 线程组 → 采样器 → Http请求(参数) → 添加监听器(察看结果树、聚合报告、用表格察看结果)
- Jmeter组件
- 测试计划:使用Jmeter测试的起点,其他组件的容器
- 线程组:代表一定数量用户
- 采样器:模拟真实各种请求
- 监听器:收集测试结果,被告知结果显示的方式
- 断言:判断请求响应的结果是否如用户所期望的,是否正确
- 处理器:前置和后置处理器
- 定时器:延迟执行
- 逻辑控制器:
- 循环控制器:
- 事务控制器:
- Jmeter参数化
- 用户自定义变量:右键 → 添加 → 配置元件 → 用户自定义变量 → kv
- 读取csv文件:
- 右键Http请求 → 添加 → 配置元件 → csv data set config
- “浏览”选择文件,设置编码格式utf-8,定义变量用逗号隔开
- 在http请求界面,调用参数${变量}
- 函数助手
- 右键Http请求,配置该有参数
- 选项 → 打开函数助手 → 选择__CSVREAD,添加文件路径,添加列序号 → 点击生成 → 复制
- 粘贴第二步的参数到http页面
- 脚本录制
- web录制
- 下载、安装badboy
- 开启badboy录制按钮,网络请求,停止
- 导出:bx、jmx
- App录制
- 同网络
- 右键 测试计划 → 添加、非测试元件、HTTP代理服务器
- 添加线程组 → 添加、逻辑控制器、录制控制器
- HTTP代理服务器修改端口号和目标控制器
- 修改手机手动代理
- 开启HTTP代理服务器“按钮”
- 手机网络请求,录制
- web录制
- Jmeter压测
- 创建JDBC connection configuration
- 变量名:
- dataurl:jdbc:mysql://localhost:3306/库名
- 驱动类:mysql jdbc driver
- mysql用户名、密码
- 创建jdbc request
- 变量名
- 选择查询类型
- 输入SQL语句
- 参数化
- cvs
- 创建JDBC connection configuration
- Jmeter压测--Windows
- 添加三方插件
- 启动server-agent
- 在Jmeter中添加监听器-jp@gc - PerfMon Metrics Collector,添加指标CPU、memory
- 线程组中添加线程数和准备时间,执行
- Jmeter压测--Linux
- 添加三方插件
- 在Linux启动server-agent
- 在Jmeter中添加监听器-jp@gc - PerfMon Metrics Collector,添加指标CPU、memory
- 线程组中添加线程数和准备时间,执行
- 概念:
十四、python
14.1 配置环境
python环境、pycharm安装
14.2 变量
14.2.1.格式:变量名=值
14.2.2.命名规则:4种
标识符只能由字母、下划线“_”、数字组成。
标识符不能以数字开头。
标识符不能使用关键字
标识符对大小写敏感。
(建议:标识符命名应“见名知意”)
14.2.3.命名方式:
小驼峰式命名法:
函数名、变量名 addName
大驼峰式命名法:
类名 AddName
14.2.4.Python中print语句
print() 方法用于打印输出,最常见的一个函数。
语法:
print(*objects, sep=' ', end='\n', file=sys.stdout)
参数:
objects -- 复数,表示可以一次输出多个对象。输出多个对象时,需要用 , 分隔。
sep -- 用来间隔多个对象,默认值是一个空格。
end -- 用来设定以什么结尾。默认值是换行符 \n,我们可以换成其他字符串。
file -- 要写入的文件对象。
14.2.4.设置换行符号:
print(a,b,c,d,e,sep=";",end="\n");
14.2.5.数据类型:number、Boolean、string、list、tuple、dictionary
14.2.6.注释:
# 单行注释
' ' '
多行注释
' ' '
14.2.7.输入输出
7.1.输入:input
7.2.输出:print(*object,sep=' ',end='\n',file=sys.stdout)
14.3 运算符
14.3.1算术运算符
+ - * / % ** //
14.3.2 逻辑运算符
and or not
14.3.3 赋值运算符
= += -= *= /= %= **= //=
14.3.4 比较运算符
> < >= <= == !=
14.4 语句
if
if 条件:
语句
if 条件:
语句
elif 条件:
语句
else:
语句
while
i=0
while(条件):
语句
i+=1
for
for i in 变量/列表/元组
语句
14.5 列表
14.5.1 格式
list= [ , , , , ]
14.5.2 增
append:拼接到最后
extend:扩转到最后(分散)
insert:插入到指定位置 (位置必须指定)
14.5.3 删除
del list []
list.pop
list.remove(元素)
14.5.4 修改
list [索引] = 修改后的值
14.5.5 查询
1.indes:获取元素索引
2.count: 计算指定元素个数
14.5.6 排序
list.sort() 排序,升序
list.reverse() 逆序
listt.sort(Reverse = True) 降序
list.sort() list.reverse 降序
14.5.7循环取值
1.for
for i in list
语句 i
2.while
i=0
while i
### 格式
变量名=(,,,,)
案例
aTuple=(23,35,56,34,11,21)
访问元组
查询个数
查询索引
修改数据(不能修改)
类型转换:列表转换元组、元组转换列表
列表转换元组
案例
aa = [23,34,45,56,67]
tuple(aa)
print(aa)
[23, 34, 45, 56, 67]
元组转换列表
案例
aTuple=('b','c','d','e','f','g')
a = list(aTuple)
print(a)
['b', 'c', 'd', 'e', 'f', 'g']
1.7 元组的循环取值
方式一:for
aTuple=('b','c','d','e','f','g')
for i in aTuple:
print(i)
方式二:while
aTuple=('b','c','d','e','f','g')
i=0
while i < len(aTuple):
print(aTuple[i])
i=i+1
`
14.5.9 字典
14.5.9.1 字典的格式
14.5.9.1.1 格式
变量名={key1:value,key2:value,,,}
14.5.9.1.2 案例'
info = {"name":"anfly","age":12,"sex":"男"}
14.5.9.2 根据键访问值
14.5.9.1.2 案例:有对应key的
info = {"name":"anfly","age":18,"sex":"男"}
print(info["name"])
#anfly
案例:无对应key的
info = {"name":"anfly","age":12,"sex":"男"}
print(info["name12"])
#KeyError: 'name12'
14.5.9.3 修改元素
字典的每个元素中的数据是可以修改的,只要通过key找到,即可修改,否则是新增
案例:对应的key
info = {"name":"anfly","age":12,"sex":"男"}
info["age"] =14
print(info)
#{'name': 'anfly', 'age': 14, 'sex': '男'}
14.5.9.4 添加元素
案例:
info = {"name":"anfly","age":12,"sex":"男"}
info["gender"] ="属鸡"
print(info)
#{'name': 'anfly', 'age': 12, 'sex': '男', 'gender': '属鸡'}
14.5.9.5 删除元素
del,clear() ---- 清空
9.5.1 del (删除指定的元素)
案例:删除整个字典
info = {"name":"anfly","age":12,"sex":"男"}
del info
print(info)
#NameError: name 'info' is not defined
案例:删除某个元素
info = {"name":"anfly","age":12,"sex":"男"}
del info["name"]
print(info)
#{'age': 12, 'sex': '男'}
9.5.2 clear清空
案例:
info = {"name":"anfly","age":12,"sex":"男"}
info.clear()
print(info)
#{}
14.5.9.6 查询长度
len():查询键值对的个数
案例
info = {"name":"anfly","age":12,"sex":"男"}
print(len(info))
#3
14.5.9.7 字典中循环
案例:取出字典中的key
info = {"name":"anfly","age":12,"sex":"男"}
for i in info.keys():
print(i)
结果:name age sex
案例:取出字典中的value
info = {"name":"anfly","age":12,"sex":"男"}
for i in info.values():
print(i)
结果:anfly 12 男
取出字典中的key和value
方式一:
info = {"name":"anfly","age":12,"sex":"男"}
for i in info.keys():
print(i,info[i])
方式二:
info = {"name":"anfly","age":12,"sex":"男"}
for k,v in info.items():
print(k,v)
14.6.1 文件
14.5.6.1.1什么是文件?
14.5.6.1.2文件的作用
使用文件的目的:保存数据存放在磁盘
把一些存储存放起来,可以让程序下一次执行的时候直接使用,而不必重新制作一份,省时省力
文件的打开与关闭
步骤:新建--写入数据--关闭
打开word软件,新建一个word文件
写入个人简历信息
保存文件
关闭word软件
同样,在操作文件的整体过程与使用word编写一份简历的过程是很相似的
打开文件
在python,使用open函数,可以打开一个已经存在的文件,或者创建一个新文件open(文件名,访问模式)
格式
f = open(‘文件’, 'w')或者f = open('文件', 'r')
如下图所示:不同的打开文件的方式
常见的文件操作有:写,读,追加
写数据(write)
格式
对象 = open("文件",w)
对象.write("写入数据")
对象.close
案例:以写的方式打开文件,写入数据
f = open('test.txt', 'w')
f.write('hello world, i am here!')
f.close()
继续写入数据
f = open('test.txt', 'w')
f.write('I love you')
f.close()
总结:
如果文件不存在那么创建,如果存在那么就先清空,然后写入数据
读数据(read)
格式
对象 = open("文件",r)
变量 = 对象.read()
print(变量)
案例:读取文件(test.txt)
f = open('test.txt', 'r')
content = f.read()
print(content)
总结:
如果用open打开文件时,如果使用的"r",
那么可以省略,即只写 open('test.txt')
如果没有文件,打开报错,存在该文件才能操作
如果文件中存在中文显示,会出现乱码需要添加encoding='utf-8'
open(‘test.txt’,”r”, encoding='utf-8')
读数据(readlines)
就像read没有参数时一样,readlines可以按照行的方式把整个文件中的内容进行一次性读取,并且返回的是一个列表,其中每一行的数据为一个元素
格式
对象 = open("文件",r)
变量 = 对象.readlines()
print(变量)
案例:读取文件(test.txt)
f = open('test.txt', 'r')
content = f.readlines()
print(content)
print(type(content))
2.1.4 读数据(readline)
readline可以按照行的方式把整个文件中的内容进行一行一行的读取
格式
对象 = open("文件",r)
变量 = 对象.readline()
print(变量)
案例,一行一行读取
f = open('a.txt', 'r', encoding='utf-8')
while True:
content = f.readline()
if content:
print(content)
else:
break
可写(a)
格式
对象 = open("",a)
对象.write("写入数据")
对象.close
案例,在文件中写入数据
f = open("test.txt",a)
f.write("新的数据")
对象.close
总结:
(可写)形式打开文件,如果文件不存在则创建并从头添加写入的内容,存在则原有数据后追加数据
读数据(rb)
格式1
对象 = open("二进制文件",rb)
变量= 对象.read()
print(变量)
格式2
with open("二进制文件","rb") as 对象:
变量 = 对象.read()
print(变量)
案例:使用尽可能多的方式实现读取图片
f = open('33.jpg', 'rb')
content = f.read()
print(content)
with open("33.jpg","rb") as rf:
res = rf.read()
print(res)
使用习惯:格式2中不需要手动关闭文件,所以经常被使用
总结
如果没有文件,打开报错,存在该文件才能操作
写数据(wb)
格式
with open("二进制文件","wb") as 对象:
变量 = 对象.write()
print(变量)
案例:备份图片
with open("1.jpg","rb") as rf:
res = rf.read()
with open("textjpg.jpg", "wb") as wf:
res = wf.write(res)
print(res)
关闭文件
格式
close( )
14.6.3文件和文件夹的操作
文件的相关操作
有些时候,需要对文件进行重命名、删除等一些操作,python的os模块中都有这么功能
3.1 文件重命名
os模块中的rename()可以完成对文件的重命名操作
格式
import os
os.rename("需要修改的文件名","新文件名")
案例:
import os
os.rename("test.txt","new.txt")
3.2 删除文件
os模块中的remove()可以完成对文件的重命名操作
格式
import os
os.remove("文件名")
案例:
import os
os.rename("new.txt")
文件夹的相关操作
2.1 创建文件夹
os模块中的mkdir()可以完成对文件的重命名操作
2.2 获取当前目录
os模块中的getcwd()可以获取当前目录
四、异常
异常处理
作用
捕捉异常可以使用try/except语句。
try/except语句用来检测try语句块中的错误,从而让except语句捕获异常信息并处理。
如果你不想在异常发生时结束你的程序,只需在try里捕获它。
2.2 语法
以下为简单的try....except...else的语法
try:
<语句> #运行别的代码
except <名字>:
<语句> #如果在try部份引发了'name'异常
else:
<语句> #如果没有异常发生
代码
try:
open("qwe.txt","r")
print("123")
except FileNotFoundError:
print("异常处理")
else:
print("没有异常")
try:
open("qwe.txt","r")
print("123")
except FileNotFoundError as result:
print("异常处理",result)
else:
print("没有异常")
2.3:使用except而不带任何异常类型
你可以不带任何异常类型使用except,如下实例
语法
try:
正常的操作
except :
发生异常,执行这块代码
else:
如果没有异常执行这块代码
代码
try:
open("qwe.txt","r")
print("123")
except :
print("异常处理")
else:
print("没有异常")
注意:以上方式try-except语句捕获所有发生的异常。但这不是一个很好的方式,我们不能通过该程序识别出具体的异常信息。因为它捕获所有的异常。
2.4:使用except而带多种异常类型
语法
try:
异常的操作
except(Exception1[, Exception2[,...ExceptionN]]]):
发生以上多个异常中的一个,执行这块代码
......................
else:
如果没有异常执行这块代码
代码
list = [1,2,3,4]
try:
open("qwe.txt", "r")
list[7]
except (NameError,FileNotFoundError) as rese:
print("出现异常")
else:
print("没有异常")
2.5:try-finally 语句
try-finally 语句无论是否发生异常都将执行最后的代码
语法
try:
<语句>
finally:
<语句> #退出try时总会执行
案例
try:
fh = open("test.txt", "r")
fh.readlines()
fh.close()
finally:
print("Error: 没有找到文件或读取文件失败")
注意:当在try块中抛出一个异常,立即执行finally块代码。
finally块中的所有语句执行后,异常被再次触发,并执行except块代码。
参数的内容不同于异常
2.6 异常的传递
代码
def func1():
print("---func1--1---")
print(num)
print("---func1--2---")
# def func2():
# print("--func2--1---")
# func1()
# print("--func2--2---")
def func3():
try:
print("---func3--1---")
func1()
print("--func3--2----")
except Exception as result:
print(result)
print("--func3---3---")
func3()
#func2()
2.7:触发异常
可以使用raise语句自己触发异常
案例:输入考生的成绩(0~100)
def functionName( score ):
if score < 0 or score >100:
raise Exception("Invalid score!", score)
# 触发异常后,后面的代码就不会再执行
functionName(200)
2.8:用户自定义异常
定义
通过创建一个新的异常类,程序可以命名它们自己的异常。异常应该是典型的继承自Exception类,通过直接或间接的方式
代码:长度不低于3为
class ShortInputException(Exception):
def init(self, length, atleast):
self.length = length
self.atleast = atleast
def main():
try:
s = input('请输入 --> ')
if len(s) < 3:
# raise引发一个你定义的异常
raise ShortInputException(len(s), 3)
except ShortInputException as result:#x这个变量被绑定到了错误的实例
print('ShortInputException: 输入的长度是 %d,长度至少应是 %d'% (result.length, result.atleast))
else:
print('没有异常发生')
main()
五、模块
Python 模块(Module),是一个Python文件,以.py 结尾,包含了Python 对象定义和Python语句
下例是个简单的模块 aa.py:
def test1():
print("我是模块1")
def test2():
print("我是模块2")
5.1:模块的引入
5.1.1:import
模块定义好后,我们可以使用 import 语句来引入模块,语法如下
import module1[, module2[,... moduleN]]
test.py 文件代码
import aa
aa.test1()
aa.test2()
#我是模块1
#我是模块2
导入python中的模块os/math
代码:开平方根
import math
print(math.sqrt(4))
#2
注意:一个模块只会被导入一次,不管你执行了多少次。这样可以防止导入模块被一遍又一遍地执行。
5.1.2:from…import 语句
Python 的 from 语句让你从模块中导入一个指定的部分到当前命名空间中,语法如下
from modname import name1[, name2[, ... nameN]]
test.py 文件代码
from aa import test1
test1()
#我是模块1
注意:只能调用导入的模块中的部分,如果想使用test2,需要如下操作
from aa import test1,test2
test1()
test2()
#我是模块1
#我是模块2
5.1.3:from…import * 语句
把一个模块的所有内容全都导入到当前的命名空间也是可行的,只需使用如下声明:
from modname import *
test.py 文件代码
from aa import *
test1()
test2()
#我是模块1
#我是模块2
扩展
使用__all__魔幻方法
当被引入的包中有__all__=(),里面指定的才能被调用,调用的时候使用from模块名 import*
aa.py
__all__=('test1','test2')
def test1():
print("我是模块1")
def test2():
print("我是模块2")
def test3():
print("我是模块2")
test.py
from aa import *
test1()
test2()
十五、单元测试
分为:单元测试、集成测试、功能测试
unittest 四大核心:
TestFixture:
主要方法:
setUp():准备环境,执行每个测试用例的前置条件;
tearDown():环境还原,执行每个测试用例的后置条件;
setUpClass():必须使用@classmethod装饰器,
所有case执行的前置条件,只运行一次;
tearDownClass():必须使用@classmethod装饰器,
所有case运行完后只运行一次;
TestCase:
TestSuite:
TestRunner:
15.1 断言
assertEqual(a,b):断言a和b是否相等,相等则测试用例通过。
assertNotEqual(a,b):断言a和b是否相等,不相等则测试用例通过。
assertTrue(x):断言x是否True,是True则测试用例通过。
assertFalse(x):断言x是否False,是False则测试用例通过。
assertIs(a,b):断言a是否是b,是则测试用例通过。
assertNotIs(a,b):断言a是否是b,不是则测试用例通过。
assertIsNone(x):断言x是否None,是None则测试用例通过。
assertIsNotNone(x):断言x是否None,不是None则测试用例通过。
assertIn(a,b):断言a是否在b中,在b中则测试用例通过。
assertNotIn(a,b):断言a是否在b中,不在b中则测试用例通过。
assertIsInstance(a,b):断言a是是b的一个实例,
是则测试用例通过。
assertNotIsInstance(a,b):断言a是是b的一个实例,
不是则测试用例通过。
15.2 生成测试报告
1:导入unittest模块 >>>import unittest
2:编写一个类继承unittest.TestCase
3:调用setUp(self), tearDown(self)方法实
现测试用例前后阶段的操作
4:编写测试用例方法
(1)该方法必须以test开头,
否则在unittest.main()中调用测试找不到该方法
(2)设置断言进行判断,输入数据和输出数据的预期结果
5:创建套件,将多个测试用例存放套件中,一并执行()
6:生成测试报告(python自带或者导入HTMLTestRunner生
成html格式的测试报告)
7:运行测试用例unittest.main(),调用测试用例中以test开头的方法
代码展示
对开发的代码块进行单元测试
开发被测代码
class Calc():
def add(self,a,b):
c =a+b
return c
def redc(self,a,b):
c = a-b
print(c)
if name == "main":
c = Calc()
c.add(2,3)
print(c.add(2,3))
单元测试代码
from day.Calc import Calc
import unittest
c = Calc() #实例化开发的类
class Test(unittest.TestCase):#unittest单元测试类必须继承unittest.TestCase
def setUp(self): #测试用例之前执行
print("start")
def test001(self):#测试用例必须test开头
res = c.add(2,1) #调取相加的方法
self.assertEqual (res,5) #断言,预期结果和实际结果的对比
def test002(self):#测试用例必须test开头
res = c.redc(2,3) #调取相减的方法
self.assertEqual (res,-1) #断言,预期结果和实际结果的对比
def tearDown(self):#测试用例结束之后执行
print("end")
if name == 'main':
unittest.main()
七、读取文件
1、创建xml文件
2、读取xml文件
from xml.dom import minidom
class Readxml():
def read_xml(self,filename,onename,twoname):
root =minidom.parse(filename)
firstnode =root.getElementsByTagName(onename)[0]
secondnode=firstnode.getElementsByTagName(twoname)[0].firstChild.data
return secondnode
具体使用
import unittest
from dev.Caculate import Caculate
from readdata.readxmldata import Readxml
c = Caculate()
r = Readxml()
a1 = r.read_xml('../data/xmltestdata.xml', 'add', 'add1')
a2 = r.read_xml('../data/xmltestdata.xml', 'add', 'add2')
a3 = r.read_xml('../data/xmltestdata.xml', 'add', 'add3')
r1 = r.read_xml('../data/xmltestdata.xml', 'reduce', 'reduce1')
r2 = r.read_xml('../data/xmltestdata.xml', 'reduce', 'reduce2')
r3 = r.read_xml('../data/xmltestdata.xml', 'reduce', 'reduce3')
class UnitTestTwo(unittest.TestCase):
def setUp(self) -> None:
print("开始")
def test001(self):
sum = c.add(int(a1), int(a2))
self.assertEqual(sum, int(a3))
def test002(self):
dif = c.reduce(int(r1), int(r2))
self.assertEqual(dif, int(r3))
def tearDown(self) -> None:
print("结束")
if __name__ == '__main__':
# unittest.main
suite = unittest.TestSuite()
caseList = ["test001", "test002"]
for case in caseList:
suite.addTest(UnitTestTwo(case))
# 运行测试用例
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)
3、读取csv文件
import csv #导入csv模块
class ReadCsv():
def read_csv(self):
item =[] #定义一个空列表
c = csv.reader(open("../commonDemo/test1.csv","r"))
#得到csv文件对象
for csv_i in c:
item.append(csv_i)
#将获取的数据添加到列表中
return item
r = ReadCsv()
print(r.read_csv())
完整代码
import unittest
from dev.Caculate import Caculate
from readdata.readcsv import ReadCsv
c = Caculate()
r = ReadCsv()
# add = c.add(1, 4)
# reduce = c.reduce(4, 1)
class UnitTestTwo(unittest.TestCase):
def setUp(self) -> None:
print("开始")
def test001(self):
pass
# self.assertEqual(add, 5)
for i in r.readCsv():
add = c.add(int(i[0]), int(i[1]))
self.assertEqual(add, int(i[2]))
# def test002(self):
# self.assertEqual(reduce, 3)
def tearDown(self) -> None:
print("结束")
if __name__ == '__main__':
# unittest.main
suite = unittest.TestSuite()
caseList = ["test001", "test002"]
for case in caseList:
suite.addTest(UnitTestTwo(case))
# 运行测试用例
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)
十六、接口自动化
16.1 get的请求
GET无参请求
r = requests.get('http://www.baidu.com')
GET传参
payload = {'key1': 'value1', 'key2': 'value2', 'key3': None}
r = requests.get('http://www.baidu.com ', params=payload)
代码
import requests
class UseRequestClass():
#get传参的第一种方式
def XWTTMethod(self):
r = requests.get
("http://v.juhe.cn/toutiao/index?type=guonei&key=
4b72107de3a197b3bafd9adacf685790")
print(r.text)
#get传参的第二种方式
def XWTTMethod(self):
params = {"type":"guonei","key":"
4b72107de3a197b3bafd9adacf685790"}
r = requests.get("http://v.juhe.cn/toutiao/index",
params=params)
print(r.text)
16.2 post请求
代码
import requests
class UseRequestClass():
def XWTTPostMethod(self):
params = {"type":"guonei","key":"4b72107de3a197b3bafd9adacf685790"}
r = requests.post("http://v.juhe.cn/toutiao/index",params=params)
#print(r.status_code)
return r.status_code