├── 15_面试问题汇总.md
├── 14_面试.md
├── 12_git.md
├── 06_测试计划.md
├── 13_自动化测试.md
├── 05_软件测试流程.md
├── 01_linux基础.md
├── 08_缺陷报告.md
├── 09_接口测试与jmeter.md
├── 10_性能测试_Fiddler_弱网测试_断点调试.md
├── 07_测试用例.md
├── 11_app与小程序测试.md
├── 02_网络基础.md
├── 03_数据库.md
└── 04_软件测试入门.md
/15_面试问题汇总.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/14_面试.md:
--------------------------------------------------------------------------------
1 | # 投递简历和面试面试
2 |
3 | 1.录音 2.自我介绍提前写好,要表明自己有干过多久,参与过什么,使用过什么工具,自己的优势,希望加入公司的意愿等 3.简历电子版为 pdf,纸质版至少打印 3 份,简历不要少于 3 页 4.不要海投 5.关闭自动回复 6.排日程表 7.接到电话时问是在哪个平台的,哪个公司,公司地址,加联系方式
4 |
--------------------------------------------------------------------------------
/12_git.md:
--------------------------------------------------------------------------------
1 | # git
2 |
3 | ## 用 git 做什么
4 |
5 | > 主要使用 git 对测试文档进行归档,
6 | > 使用 git clone 将远程仓库初始化到本地
7 | > 在本地新建文件
8 | > 通过 git add 将文件添加到缓存区
9 | > 通过 git commit -m 创建版本并提交到本地仓库
10 | > 如果是对文件修改可以使用 git commit -am
11 | > 通过 git push 将本地仓库推送到远程仓库
12 | > 可以用 git pull 将远程仓库文件拉取到本地
13 |
--------------------------------------------------------------------------------
/06_测试计划.md:
--------------------------------------------------------------------------------
1 | # 测试计划
2 |
3 | ## 需求从哪里来?
4 |
5 | 项目初期由项目经理和客户沟通,得到项目需求文档和产品原型图,项目组成员会在需求评审之前拿到需求文档,进行研读,然后在需求评审会议上进行评审
6 |
7 | ## 需求评审会议的时候测试需要做什么?
8 |
9 | 首先,测试需要了解业务流程,关注需求的功能是否易于理解,功能间是否存在冲突,业务之间的逻辑是否通顺,需求描述的是否清晰准确,是否有二义性描述,功能是否有明确的约束限制,比如输入内容的长短、组成,了解项目的周期,任务的优先级,提测时间是否明确,各开发和测试人员任务划分情况
10 |
11 | ## 需求如何不明确如何处理?
12 |
13 | 充分研读需求文档和产品原型图,在需求评审会上提出,只有明确需求才能更好的完成工作,后续还有问题可以找产品经理提出
14 |
15 | ## 测试工作中如果公司没有需求怎么办?
16 |
17 | 如果项目已经开发了,根据实际项目了解项目流程和业务;如果没有开发,要通过项目组了解项目基本情况和项目背景,充分和项目组成员了解。熟悉后使用思维导图划分相应模块,提取相应测试点,整理测试文档,如果遇到问题,要和项目组成员产品经理进行沟通
18 |
19 | ## 测试计划是谁写的,有哪些内容
20 |
21 | 是在需求评审会议之后由测试老大写的,如果没有时间,我们也会自己编写测试计划。
22 | 包含测试背景,测试环境,测试目的,测试采用的方法,测试模块,任务安排/人员安排,里程碑,风险分析
23 |
--------------------------------------------------------------------------------
/13_自动化测试.md:
--------------------------------------------------------------------------------
1 | # 自动化测试(软件测试方向了解即可)
2 |
3 | python 自动化脚本编写教程:[selenium+python+unittest 实现自动化测试(入门篇)](https://blog.csdn.net/a836586387/article/details/88899936)
4 |
5 | ## 自动化测试怎么做的
6 |
7 | > 首先制定自动化测试计划,明确对象和目的,确认并构筑好必要资源【安装对应的库、构造测试数据】,分析提取自动化相关测试点,一般是提取流程相关、正向流程、比较繁琐的测试点,主要是进行回归测试,主要采用 python+selenium 结合 po 模式进行自动化测试,
8 | >
9 | > 首先新建项目,在项目下新建
10 | > Base 【基础类,对 selenium 底层代码进行二次封装】,
11 | > Common【存储公共类和方法:发送邮件、工具类、读取 excel 文件】,
12 | > Data 【进行参数化的 excel 文件】,
13 | > Out【输出文件,错误截图,测试报告,测试日志】,
14 | > Location【元素定位相关代码文件】,
15 | > Page【页面业务逻辑,操作相关方面】,
16 | > Testcase【存放 unittest 相关测试用 4 例,调用 page 文件夹下的代码】
17 | > 相关文件夹。
18 | >
19 | > 并且会使用数据驱动方式,引入 ddt 模块,进行参数化。最后会在项目下创建运行所有测试用例的文件,一般命名为 run_all. Py,里面主要是测试套件整合相关代码,已经通过 unittest 生成测试报告,发送项目邮件给项目组成员的相关代码
20 |
21 | ## 元组和列表的区别
22 |
23 | > 定义方式不同,() 和 []
24 | > 如果只有一个元素,元组需要在元素后加逗号,列表不用
25 | > 元组不可以修改,列表可以修改
26 |
27 | ## 三大等待的区别
28 |
29 | > 强制等待:强制休眠固定时间,休眠之后执行代码
30 | > 隐式等待:所有元素都进行等待,通过不断轮询,直到找到元素结束等待,或超时为止
31 | > 显式等待:针对某一元素进行单独等待,可以设置总等待时间和轮询时间
32 |
33 | ## 元素定位不到的原因
34 |
35 | > 页面未加载完:等待页面加载完再定位元素
36 | > 动态 id:使用 Xpath 或其他方式定位
37 | > 使用了 frame 框架:切换到框架内进行定位
38 | > 弹窗:使用 js 脚本工具锁定界面进行定位
39 |
40 | ## 自动化测试的难点
41 |
42 | > 维护成本高,稳定性,元素可能定位不到,多用显式等待定位元素
43 |
--------------------------------------------------------------------------------
/05_软件测试流程.md:
--------------------------------------------------------------------------------
1 | # 软件测试流程
2 |
3 | ## 原则
4 |
5 | 1. 一切追溯到用户的需求
6 | 2. 应该把"尽早测试和不断测试"作为测试人员的座右铭
7 | 3. 二八原则:80%的错误,发生在 20%的模块中
8 | 4. 穷举测试是不可能的
9 | 5. 第三方测试会更客观
10 | 6. 测试用例是设计出来的,不是写出来的
11 | 7. 不可将测试用例置之度外,排除随意性
12 | 8. 测试贯穿于整个生命周期
13 | 9. 对发现错误较多的程序段,应进行更深入的测试
14 | 10. 妥善保存一切文档,便于后期进行复用
15 |
16 | ## 基本流程(重要)
17 |
18 | 产品经理和客户对接,将客户的需求转换产品需求(需求文档和产品原型图),产品将需求文档发给项目组各个成员,我对文档进行研读。开需求评审会议,产品阐述需求,项目成员理解需求,提出问题,去除歧义。会议后,由测试老大编写测试计划,测试计划评审会(测试,项目经理)。编写测试用例,测试用例评审会议(测试,项目经理,开发)。等待开发提测。如果是前后端分离的项目首先测试接口。产品功能测试,首先进行冒烟测试,系统测试(功能,非功能,ui,易用性,兼容性,网络,性能,安全)。如果发现问题,我们会提交问题给开发,开发修复好之后我们会进行功能回归测试,2-3 轮系统回归测试,如果时间充足,我们还会进行交叉测试。我们输出测试时报告,给出是否上线结论。运维上线。
19 |
20 | ### 需求分析阶段
21 |
22 | 越多需求,理解需求,分析需求,参加需求评审会议
23 |
24 | ### 测试计划阶段
25 |
26 | 编写测试计划,参与测试计划评审工作
27 |
28 | ### 测试设计阶段
29 |
30 | 参考需求文档、接口文档、详细设计编写测试用例,与开发、产品经理沟通
31 |
32 | ### 测试执行阶段
33 |
34 | ```mermaid
35 | flowchart LR
36 | cs1["测试环境:内部测试的环境"]--测试通过-->cs2["生产环境:用户使用的环境"]
37 | ```
38 |
39 | - 搭建测试环境,准备数据,执行冒烟测试,进入正式测试,提交 bug
40 |
41 | ### 评估阶段
42 |
43 | 出测试报告,对整个测试过程进行评估
44 |
45 | ## Bug 处理流程
46 |
47 | 发现问题,提交到缺陷管理平台,督促开发确认和解决,开发确认并修复后,对缺陷进行回归验证,如果验证通过,关闭 bug,如果验证失败,开启 bug,协助开发修复 bug。
48 |
49 | ## 软件测试开始结束挂起测试的标准
50 |
51 | 开发提测后,冒烟测试通过后可以开始测试
52 | 出现致命问题,导致 30% 以上测试用例无法执行,一般很少出现这种情况,会挂起
53 | 开发修复完成,可执行进一步操作可以继续测试
54 | 测试用例 100% 执行, 软件产品的 bug 修复率在 95 以上, 并且不存在一般级别以上的 bug, 如果存在一般级别以上的 bug, 需要产品经理和项目经理协商, 由他们觉得是否可以上线
55 |
--------------------------------------------------------------------------------
/01_linux基础.md:
--------------------------------------------------------------------------------
1 | # Linux 基础
2 |
3 | ## 1.操作系统定义和作用
4 |
5 | 操作系统直接运行在计算机上的系统软件, 它是控制硬件和支持软件运行的计算机程序。
6 | 向下控制硬件向上支持软件的运行,具有承上启下的作用。
7 |
8 | ## 2.常用虚拟机软件
9 |
10 | - VMware
11 | - VirtualBox
12 |
13 | ## 3.在虚拟机上安装 Linux
14 |
15 | 推荐几个教程,也可以自己去搜,网上有很多详细教程。
16 |
17 | [VMware 虚拟机安装 Linux 教程(超详细)-七维大脑](https://blog.csdn.net/weixin_52799373/article/details/124324077)
18 |
19 | ## 4.Linux 常用命令(重要)
20 |
21 | - `ls`:列出目录下的文件
22 | - `pwd`:显示当前工作目录
23 | - `clear`: 清屏
24 | - `cd`:切换目录
25 | - `touch`:创建文件
26 | - `mkdir`:创建目录
27 | - `rmdir`:删除目录
28 | - `rm`:删除文件,`-r`递归删除文件,`-f`强制删除文件
29 | - `cp`:复制文件
30 | - `mv`:移动文件
31 | - `cat`:查看文件内容
32 | - `echo`:输出内容到文件
33 | - `find`:查找文件,`-name`: 查找文件名,一般使用通配符`*`表示 0 或多个字符,`?`表示一个字符
34 | - `grep`:查找文件中包含指定字符串的行
35 | - `chmod`:修改文件权限,一般使用数字法,`-R`递归修改文件权限,可读为`4`,可执行为`1`,可写为`2`
36 | - `tail`:显示文件的后几行
37 | - `vi`、`vim`:编辑文件
38 | - `>`: 将文件内容重定向到另一个文件(覆盖)
39 | - `>>`: 将文件内容重定向到另一个文件(追加)
40 |
41 | \*软硬连接、正则表达、压缩、用户操作做了解即可
42 |
43 | ## 5.ssh
44 |
45 | 使用`ssh 用户名@主机名`登录主机
46 |
47 | # 6.重点要记的命令
48 |
49 | `ifconfig` 查看网卡的配置
50 | `ifconfig ethX up` 启用 'ethX' 网卡设备信息
51 | `ifconfig ethX down` 禁用 'ethX' 网卡设备信息
52 | `ping IP/域名` 测试从本机到对方网络的连通性
53 | `du -h filename` 以适合的方式查看文件占用磁盘空间大小
54 | `du -sh dirname` 查看指定文件目录下磁盘占用量
55 | `tail -f filename` 动态显示文件内容(默认后 10 行) (可通过 echo 重定向演 示)
56 | `export` 环境变量查看
57 | `export env="value"` 添加环境变量
58 | `wget url` 下载文件
59 | `wget url -O filename` 下载文件并重命名
60 | `uname -a` 显示内核版本
61 | `cat /etc/redhat-release` 查看 centos 版本
62 | `ps -aux` 或 `ps -ef` 显示进程状态
63 | `kill pid` 停止某进程
64 | `kill -9 pid` 强制杀掉进程
65 | `history` 显示历史输入的命令
66 | `top` 动态的显示系统耗费资源最多的进程(P 按 cpu 排序 M 按 memory 排序 Q 退出)
67 | `poweroff` 关机
68 | `reboot` 重启
69 | `free` 显示内存使用情况( `-k` 以 KB 为单位,`-m` 以 MB 为单位,`-g` 以 GB 为单位)
70 | `systemctl status firewalld` 查看防火墙状态
71 | `systemctl stop firewalld` 关闭防火墙
72 | `netstat -an` 查看端口使用情况
73 | `du -h --max-depth=0 *` 查看当前目录文件及文件夹大小
74 | `ps -ef | grep 'xxx' |awk '{print $2}' |xargs kill -9` 停止包含 xxx 相关的进程
75 |
--------------------------------------------------------------------------------
/08_缺陷报告.md:
--------------------------------------------------------------------------------
1 | # 缺陷报告
2 |
3 | ## 缺陷报告包含哪些内容
4 |
5 | 缺陷的标题,缺陷的详细描述,缺陷的复现步骤,预期结果和实际结果的对比,如果可以的话我们还会提供操作步骤的录屏,bug 的模块,bug 的优先级,bug 的处理人
6 |
7 | ## 缺陷的严重程度
8 |
9 | > (1) Fatal 致命的缺陷
10 | > 造成系统或应用程序崩溃、死机、系统挂起,或造成数据丢失,主要功能完全丧失,导致本模块以及相关模块异常等问题,数据损坏,项目无法进行
11 | > (2) Critical 严重错误的软件缺陷
12 | > 系统的主要功能部分丧失、数据不能保存,系统的次要功能完全丧失。问题局限在本模块,导致模块功能失效或异常退出。如致命的错误声明,程序接口错误,数据库的表、业务规则、缺省值未加完整性等约束条件。
13 | > (3) Major 一般的软件缺陷
14 | > 次要功能没有完全实现但不影响使用。如:操作时间长,模块功能部分失效等,
15 | > (4) Minor 较小的软件缺陷
16 | > 较小错误,提示信息不太准确,或用户界面差,的软件缺陷,使操作者不方便或遇到麻烦,但它不影响功能性的操作和执行,如错别字、界面不规范等,文字排版,ui 样式
17 | > (5) Enhancemental 建议问题
18 | > 由问题提出人对测试对象的改进意见或测试人员提出的建议、质疑
19 |
20 | ## 缺陷的优先级
21 |
22 | > 由于缺陷的等级,当前模块重要程度不一样, 导致处理缺陷的先后顺序不一样, 一般分为下面几种:
23 | > (1) P 1 立即解决
24 | > 缺陷导致系统几乎不能完全运行、使用,或严重妨碍测试的执行,需立即修正、尽快修正;
25 | > (2) P 2 高优先级
26 | > 缺陷严重,影响测试,需要优先考虑修正,如不超过 24 小时修正;
27 | > (3) P 3 正常级别
28 | > 缺陷需要修改, 只要正常排队修复就可以
29 | > (4) P 4 低优先级
30 | > 缺陷可以在开发人员有时间的时间修复, 若没时间可以不修正
31 |
32 | ## 缺陷管理目的
33 |
34 | > 1. 保证信息的一致性;
35 | > 2. 保证缺陷得到有效的跟踪,缩短沟通时间,解决问题更高效;
36 | > 3. 收集缺陷数据并进行数据分析,作为缺陷度量的依据。
37 |
38 | ## 验收标准
39 |
40 | > DI: Defect Index (缺陷率)
41 | > 定义:DI 值是衡量软件质量的高低的指标之一。
42 | > 公式:DI= 致命级别的问题个数\*10+ 严重级别的问题个数\*3+ 一般级别的问题个数\*1+ 提示级别的问题个数\*0.1
43 | >
44 | > 1、测试执行标准(执行测试标准):
45 | > 1.1 测试用例要完全覆盖需求,测试用例要 100% 执行
46 | >
47 | > 2、测试缺陷通过标准(上线标准)
48 | > 2.1 BUG 修复率在 95% 以上,并且不存在一般级别以及以上 BUG
49 | > 2.2 如果存在一般级以上的 BUG 要经过产品经理及项目负责协调决定可遗留数量
50 |
--------------------------------------------------------------------------------
/09_接口测试与jmeter.md:
--------------------------------------------------------------------------------
1 | # 接口测试
2 |
3 | ## 接口流程
4 |
5 | 从开发那拿到接口文档 (word,在线),熟悉接口业务,比如说像接口的内容,接口的功能,接口的地址和请求方式,参数类型,约束限制 ,返回的数据格式 (内容),状态码,示例模板以及接口之间存在的依赖关系等,了解熟悉后我们会进行接口用例设计,设计完成之后我们会进行接口测试,我们通常使用 jmeter 工具进行接口测试,接口测试完成后输出接口测试报告。
6 |
7 | ## 测试接口用例如何设计?
8 |
9 | 主要考虑接口的出参和入参,入参主要考虑参数的默认值,必填项,长度,组成规则,数据类型和业务约束。出参主要考虑返回数据的准确性,以及数据排序规则,除此之外还要考虑接口本身的业务限制,还有幂等性测试,越权访问,token 失效验证,错误状态码的覆盖还要考虑接口新旧版本的兼容性。
10 |
11 | ## jmeter (接口测试工具) 是如何使用的?
12 |
13 | 首先我们在 jmeter 的测试计划下,会新建一个 http 请求默认值,来填写接口所用到的域名和端口号,然后在测试计划下面添加线程组,在线程组下添加 http 信息头管理器,添加该接口请求时必要的头信息,比如 token 值,如果参数是 json 格式还需要添加 content-type 为 application/json 格式,然后添加 http 取样器,在取样器中输入接口路径,请求方式,参数等内容,还可以将设计好的测试用例,通过 csv 参数化的方式传入到请求的参数中,如果接口间有相互调用 (关联) 关系,比如上一个接口返回的数据要在下一个接口中使用,我还会用到关联技术,通过后置处理器中的 json 提取器或正则表达式提取器提取参数数据保存在变量当中,在需要调用的地方,输入 ${}的方式进行调用,如果是跨线程组关联的话还需要用到 Setproperty 函数和 Bean Shell 取样器,将局部变量提升为全局变量,然后添加断言来判断响应结果的正确性,最后添加查看结果树来查看结果。
14 |
15 | ## 接口测试的重点和难点是什么?
16 |
17 | 重点:分析好接口内容,了解好接口的功能,还有接口之间的关系,还有各个参数和返回信息的含义。
18 | 难点:要对前后端业务处理逻辑非常清楚,知道接口传递的参数哪些是必要的,哪些是必须返回的数据,还有了解接口之间的依赖关系.
19 |
20 | ## 接口测试中发现 bug 可能是什么?
21 |
22 | 1.接口参数没有进行异常处理,有些空值,组成规则不对的,边界值超长,缺参的情况,没有给出正确的错误提示, 2.返回的敏感信息没有加密,比如说用户的身份证,姓名,银行卡信息没有加密,加密后前端解密再展示给用户看。 3.没有进行恶意的请求拦截,被人可以对我们进行恶意攻击,一直给我们接口压力,我们做的是每分钟同一个 IP 地址只能提交 120 次 4.接口性能问题,某一个接口并发,同一时间,如果提交多条数据,响应时间过长,有请求报错的情况。
23 |
24 | ## 怎么验证接口是正确的?
25 |
26 | 要验证接口返回数据的准确性,接口返回内容是否准确,出参的参数没有缺失,排序规则正确,还要去数据库进行验证
27 | 确认接口返回的状态码正确,包括正常和异常,接口返回的数据与提示信息是否准确,接口返回数据的排序是否正确,最后验证返回数据和数据库中数据是否一致。
28 |
29 | ## 接口自动化怎么实现的?
30 |
31 | 通过 jmeter 来实现接口自动化,首先从开发那拿到接口文档,了解接口的内容,功能业务和接口之间相互关系,接着编写接口测试用例,在 jmeter 中添加脚本,首先对公共信息添加请求默认值,比如协议,域名,端口号,字符集等,然后给每个接口添加一个线程组,如果有请求头信息,还需添加请求头管理器,比如有些接口需要 token 值,或请求体格式为 content-type 为 application/json,接下来在线程组中添加 http 取样器,通过 csv 参数化的方式进行接口测试数据参数化,并调整线程组循环次数,与参数化参数数量一致,如果接口之间有相互关联关系我们还需要用到关联技术,比如上个接口返回的数据要在下个接口中使用,要用到 json 提取器或正则表达式提取器对返回数据进行提取,通过 setproerty 和 Bean shell 提升为全局变量,使用 property 函数在使用的地方调用,添加断言判断响应信息的准确性,最后通过 nat 工具自动生成测试报告。
32 |
33 | ## 接口测试报告怎么写的
34 |
35 | 使用 ant 自动生成测试报告,下载配置 ant 环境变量,创建 ant 所需的 build. Xml 文件,在文件中填写 jmeter 脚本路径、结果输出路径、测试报告输出路径,修改 jmeter 配置文件,将返回数据限制打开,在 build. Xml 文件所在路径在终端中使用 ant 输出测试报告。
36 |
37 | ## 如何搭建测试环境
38 |
39 | 主要由运维搭建,我也搭建过几次,通过宝塔面板搭建的,首先通过宝塔一键安装 lnmp 服务器架构。
40 |
41 | 前后端不分离的项目,先创建站点,在站点的路径导入代码包并解压,之后初始化数据库,通过 switchhost 进行域名解析,之后就可以使用了。
42 |
43 | 前后端分离的项目,java 相关项目,先安装 jdk 和 tomcat,然后在新建站点目录下导入后端代码包,再导入前端静态代码,最后初始化数据库配置好 nginx 代理,比如代理后端的接口地址,进行域名解析后就可以访问。
44 |
--------------------------------------------------------------------------------
/10_性能测试_Fiddler_弱网测试_断点调试.md:
--------------------------------------------------------------------------------
1 | # 性能测试
2 |
3 | ## 性能测试流程
4 |
5 | > 首先确认性能需求,分析业务场景,一般主要测试重要的业务场景以及并发较多的场景。
6 | > 先制定性能测试计划,构造测试数据,运用参数化关联、断言、事务控制器、集合点来定义测试场景,并编写性能测试脚本。一般进行并发测试,首先在 jmeter 测试计划下添加线程组、事务控制器,在事务控制器中添加相关事务的 http 请求,添加固定定时器用于模拟用户的思考时间,添加同步定时器模拟并发操作,设置线程组的线程数模拟用户数,修改线程的持续运行时间,通过参数化进行参数传递,编写断言判断响应的结果状态,多次复制线程递增修改线程的数量和同步定时器并发数,通过 jmeter 指令的方式运行脚本,最后生成测试报告,分析测试结果。
7 |
8 | ## 怎么判断服务器性能
9 |
10 | > 通过梯度施压进行性能测试,通过最佳并发用户数,通过多个指标判断。
11 | >
12 | > 指标数据可以通过 jmeter 的 perfmon 插件和生成的性能测试报告一起分析。
13 | > 考虑的指标包括,响应时间、请求错误率、服务器 cpu、内存、tps 等指标综合判定。
14 | >
15 | > 随着用户数的增加,tps 也跟随着线性增加,响应时间在 3 秒以内,cpu 和内存使用率在 70% 以内,此时就是最佳并发用户数。
16 | >
17 | > 如果 tps 随着用户数缓慢增加,响应时间在 5 秒以内,cpu 和内存使用率在 90% 内,此时就是最大并发用户数。
18 |
19 | ## 有做过性能调优吗
20 |
21 | > 1. 先考虑网络问题,可以通过 ping 查看与服务器通讯是否正常,查看传输速度快慢。如果有问题可以提升服务器带宽,看响应时间是否得到优化。
22 | > 2. 考虑数据库问题,可以单独对数据库进行压测,使用 jmeter 的 jdbc 压测服务器,查看数据库最大连接数,考虑 sql 语句的执行效率,索引命中率等问题。
23 | > 3. 考虑中间件问题,查看中间件设置最大连接数是否合理,比如 nginx,如果最大连接数过小也会导致等待时间过长。
24 | > 4. 考虑服务器硬件配置,cpu、内存、磁盘等,如果有问题可以进行升级服务器。
25 | > 5. 考虑开发代码效率问题,看是否需要优化代码。
26 |
27 | # Fiddler
28 |
29 | ## 你是如何判断前后端问题的
30 |
31 | > 使用 Fiddler 工具对数据进行抓包,主要从接口请求和响应数据进行分析
32 | > 如果请求的地址、方法、请求体、参数中出现问题,是前端问题
33 | > 如果请求的数据正确,响应数据错误,比如出参内容错误,响应数据排序错误,是后端问题
34 | > 还可以通过状态码判断,4 xx 是前端问题,5 xx 是后端问题
35 | > 如果请求响应数据正确,前端显示有问题,是前端问题
36 | > 一般界面样式问题是前端问题
37 | > 数据交互问题一般是后端问题
38 |
39 | ## Fiddler 如何抓取 https 请求
40 |
41 | > 在 Fiddler 设置中开启抓取 https 请求选项
42 | > 开启解析 https 请求数据选项
43 | > 勾选忽略证书错误
44 | > 下载并安装 Fiddler 证书
45 | > 重启就可以抓取到 https 请求
46 |
47 | ## 这么抓取手机 app 数据
48 |
49 | > 1. 设置开启允许远程连接选项,并开启抓取 https 选项
50 | > 2. 确保手机和 Fiddler 主机在同一局域网内,手机 wifi 设置代理为 Fiddler 所在主机 ip 地址,端口号设为 8888
51 | > 3. 浏览器打开主机 ip 地址端口 8888,下载 Fiddler 证书
52 | > 4. 打开 app 就可以进行抓包
53 |
54 | ## 如何进行 mock 挡板测试
55 |
56 | > 一般在需要调用第三方接口时,第三方接口需要收费或未完成,的情况下进行挡板测试
57 | > 首先在 Fiddler 选择 AutoResponder 选项,添加规则,在规则中添加需要进行挡板测试的网址
58 | > 创建响应数据文件,内容中编写好响应信息
59 | > 启用此规则,就可以进行挡板测试
60 |
61 | ## Fiddler 主要用来做什么
62 |
63 | > 用于数据抓包
64 | > 定位前后端 bug
65 | > 验证数据准确性和安全性
66 | > 构造弱网环境进行弱网测试
67 | > 进行 mock 挡板测试
68 | > 进行断点调试,篡改请求和响应内容
69 |
70 | ## Fiddler 如何进行弱网测试
71 |
72 | > > 在 Fiddler 设置中开启抓取 https 请求选项
73 | > > 开启解析 https 请求数据选项
74 | > > 开启允许远程连接选项
75 | > > 确保手机和 Fiddler 主机在同一局域网内,手机 wifi 设置代理为 Fiddler 所在主机 ip 地址,端口号设为 8888
76 | > > 下载 Fiddler 证书
77 | >
78 | > 在 Fiddler 调整脚本,限制上传和下载的速度,开启限速选项
79 |
80 | ## 弱网测试目的
81 |
82 | > 查看程序在网络异常的环境下能否正常运行或正常处理网络异常相关错误
83 | > 在加载缓慢的情况下是否有加载提醒或动画
84 | > 无法加载到的时候有没有默认提示信息,图片有没有默认图片
85 | > 查看在弱网环境下是否有重复提交问题
86 |
87 | ## 怎么做断点调试的
88 |
89 | > 分为请求前断点和响应后断点
90 | > 请求前断点可以修改请求相关信息,通过 bpu 指令打请求前断点
91 | > 响应后断点可以修改响应相关信息,通过 bpafter 指令打响应后断点
92 | > 主要用断点调试模拟篡改数据,查看前后端能否对异常数据异常处理
93 |
--------------------------------------------------------------------------------
/07_测试用例.md:
--------------------------------------------------------------------------------
1 | # 测试用例
2 |
3 | ## 测试用例如何写
4 |
5 | 参考需求文档,充分熟悉产品业务需求,提取产品的测试点,运用好测试用例设计方法,步骤场景清晰,尽量覆盖测试场景,包括显性需求和隐性需求,既要覆盖功能特性,又要覆盖非功能特性界面易用性兼容性网络安全性能等方面,覆盖到所有的业务逻辑,覆盖到所有的典型用户场景,覆盖到所有需求点,最终尽量没用冗余的测试用例。
6 |
7 | ## 用例包含哪些内容
8 |
9 | 用例编号、用例标题、功能模块、优先级、前置条件、输入数据、操作步骤、预期结果
10 |
11 | ## 测试用例级别根据什么划分
12 |
13 | 根据用户使频率进行划分
14 |
15 | ### 测试用例的要素
16 |
17 | 1). 测试用例编号
18 | 编号由字符和数字组合成的字符串, 用例编号具有唯一性、容易识别, 如下表
19 | 2). 测试项目
20 | 测试的项目属于哪个项目或者被测试的需求、被测的模块、被测的单元等等
21 | 3). 预置条件
22 | 执行当前测试用例需要的前提条件, 如果前提条件不满足, 则后面的测试步骤不能进行或者得不到预期结果
23 | 4). 测试输入
24 | 测试用例执行过程中需要加工的外部信息. 根据测试用例的具体条件有手工输入、数据库等
25 | 5). 预期输出
26 | 测试用例的预期输出结果, 包括返回值内容、界面响应结果等.
27 | 6). 操作步骤
28 | 执行当前测试用例需要经过的操作步骤,需要明确的给出一个步骤的描述,测试用例执行人员可以根据该步骤完成测试用例执行
29 | 7). 测试用例标题
30 | 对测试用例的简单描述。用概括的语言描述该测试用例的测试点。每个测试用例的标题不能够重复,因为每个测试用例的测试点事不一样的。
31 | 8). 级别
32 | 对于测试用例的重要程度的区分. 包含如下几种:
33 |
34 | - 高级别
35 | 保证系统基本功能、核心业务、重要特性、实际使用频率比较高的用例
36 | - 中级别
37 | 重要程度介于高和低之间的测试用例
38 | - 低级别
39 | 实际使用的频率不高,对系统业务功能影响不大的模块或功能的测试用例
40 |
41 | > 用例中包含那些内容?
42 | > 用例编号,用例标题,功能模块,优先级,前置条件,输入数据,操作步骤,预期结果
43 | >
44 | > 测试用例的级别根据什么划分的?
45 | > 根据用户使用的频率进行划分,经常使用的模块优先级高,不经常使用的优先级低
46 |
47 | ## 测试用例设计方法
48 |
49 | > 等价类划分法:有效等价类,无效等价类,举例输入框只能输入英文和数字
50 | > 边界值法:有范围限制的,长度,取边界的点和边界相邻的点,输入框有长度限制
51 | >
52 | > 常用于多条件、多结果、多组合场景
53 | > 因果图法
54 | > 正交表法
55 | > 判定表法
56 | >
57 | > 场景法:用各种场景覆盖可能的业务流程,基本流备选流,用户购物流程
58 | > 错误推测法:根据以往经验,对可能出现的错误进行推测,用户注册情况
59 |
60 | ## 测试用例如何写的请举例说明?都包含哪些内容?测试用例的级别根据什么划分的?
61 |
62 | 参考需求文档,充分熟悉产品的业务和需求,提取项目的测试点,运用好测试用例的测试方法 (等价类, 边界值, 判定表, 错误推测…),步骤场景清晰,尽量去覆盖所有的测试场景,包括显性需求和隐性需求,既要考虑功能又要考虑非功能 (UI, 易用性, 兼容性, 网络, 安全, 性能) 质量特性, 覆盖到所有的业务逻辑, 覆盖到所有的典型的用户场景, 覆盖到所有的需求点, 最终尽量没有冗余的测试用例.
63 |
64 | ## 你们测试执行的标准是什么?
65 |
66 | 测试用例要完全覆盖需求, 测试用例要 100% 执行
67 |
68 | ## 如何保证你设计的测试用例完全覆盖需求?
69 |
70 | 充分了解需求文档,采用测试用例设计方法,既要考虑功能,非功能 (界面, 易用性, 兼容性, 网络, 性能, 安全), 尽量覆盖所有用户场景, 同时还要进行测试用例评审, 进行查漏补缺, 有时间进行交叉测试.
71 |
72 | ## 测试用例是怎么评审
73 |
74 | 一般在测试用例写完之后进行测试用例评审工作,我们会和开发以及测试团队成员一起进行测试用例评审,评审目的是为了找出是否有重复的测试用例,完善测试用例的覆盖率。
75 | 评审时间在半个小时到一个小时,评审方式是每个人阐述自己的测试用例,先对复杂的、优先级高的、疑问多的用例进行评审,如果时间紧,优先级低的用例先不进行评审。评审之后整理测试用例,把修改之后的用例进行补全,修改的内容用黄色标记,新增内容用绿色标记,有疑问的内容用红色标记。最终把测试用例交给老大最终审查,如果没有问题就按照测试用例执行测试。
76 |
77 | ## 非功能点怎么考虑的
78 |
79 | - 界面 ui,检查界面是否与原型图和 ui 设定图一致,界面风格布局样式字体文字大小是否一致,是否有错别字,内容过长是否换行截断隐藏。图片是否显示正确,是否被裁剪拉伸。
80 | - 易用性,是否支持快捷键,文字描述清晰易懂,操作流程简介易于理解,页面焦点是否合理,是否有新功能引导。
81 | - 兼容性,web 兼容性考虑不同浏览器版本内核分辨率。需求有的测需求有的,未有的找前十浏览器。app 兼容性考虑不同手机品牌型号系统版本分辨率屏幕类型。安卓 10-13,ios 12-16. 屏幕 6.4-6.8 寸,10802400,10802340,14402560,14003200.
82 | - 网络,弱网环境下是否正常,断网重连,网络切换。
83 | - 性能,客户端性能,加载速度流畅度,占用资源情况。服务器性能,最大并发用户数,cpu 内存吞吐量响应时间响应成功率
84 | - 安全,加密,掩码,越权访问,密码错误次数限制,
85 |
--------------------------------------------------------------------------------
/11_app与小程序测试.md:
--------------------------------------------------------------------------------
1 | # app 测试
2 |
3 | > 主要从功能和专项方面考虑
4 | > 功能方面主要考虑 app 功能、业务逻辑、数据交互是否正常,是否满足需求文档要求
5 | > 除此之外考虑 app 启动,热启动【锁屏,后台】、冷启动
6 | > 考虑 app 首次打开的授权权限问题
7 | > 考虑 app 内部层级关系是否过深
8 | > 清除文件,清除缓存,杀死后台进程
9 | > 广告,跳转,错误引导
10 |
11 | > 专项测试
12 | >
13 | > > 安装卸载更新
14 | > >
15 | > > > 初次安装,卸载安装,覆盖安装,新版本覆盖旧版本,旧版本覆盖新版本
16 | > > > 强制更新,非强制更新
17 | > > >
18 | > > > > 不更新能不能使用
19 | > > > > 拒绝更新是否还有提示,能否正常操作
20 | > > > > 更新下载一半下次能否继续更新
21 | >
22 | > 中断交叉事件
23 | >
24 | > > 关机,闹钟,来电,短信
25 | >
26 | > 兼容
27 | >
28 | > > 手机系统,系统版本【android 9-14,ios 12-17】,品牌,分辨率【10802400、10202340、14402560、14003200】,尺寸【6.4-6.8】,屏幕类型
29 | >
30 | > 网络
31 | > 性能
32 | > 稳定性
33 |
34 | # qnet 怎么用
35 |
36 | > 选择弱网环境模板,比如 2 g、3 g、地铁,也可以手动设置参数【带宽,延迟抖动,丢包】
37 | > 选择 app 启动
38 |
39 | ## Adb
40 |
41 | ```powershell
42 | 查看现有设备
43 | adb devices
44 | 启动adb服务
45 | adb start -server
46 | 关闭adb服务
47 | adb kill-server
48 | 安装apk
49 | adb install apk地址
50 | 覆盖安装
51 | adb install -r apk地址
52 | 将电脑文件拷贝到手机
53 | adb push
54 | 将手机文件拷贝到电脑
55 | adb pull
56 |
57 |
58 |
59 | 进入shell环境
60 | adb shell -s 设备名
61 | 搜索设备当前运行的包名或页面名
62 | adb shell dumpsys window w | findstr name=
63 | 查看指定app日志
64 | adb shell "logcat | grep 包名"
65 | 查看安装的包
66 | adb shell pm list package -f
67 | 查看第三方包名
68 | adb shell pm list package -3
69 | 查看包安装路径
70 | adb shell pm path 包名
71 | 启动
72 | adb shell am start 包名/页面名
73 | 停止
74 | adb shell am force-stop 包名
75 | 查看网卡信息
76 | adb shell ifconfig
77 | 查看网络连通性
78 | adb shell ping ip地址
79 |
80 | ```
81 |
82 | ## monkey 怎么用
83 |
84 | > 一般对 app 进行稳定性、压力测试时使用 monkey
85 | > 先下载配置 jdk 和 androidSDK 环境
86 | > 执行 adb shell monkey -p 包名 -s 种子数 --throttle 延迟
87 | > 还可以设定时间百分比选项 --pct-touch 点击事件,--pct-motion 移动事件,--pct-syskeys 系统按键事件
88 | > 还可以添加忽略错误 --ignore-crashes 忽略崩溃,--ignore-timeouts 忽略 anr 错误
89 | > -v 设置日志详细程度
90 | > 加随机事件次数,一般 5w-10w 条
91 |
92 | ## monkey 测试如何进行结果分析
93 |
94 | > 通过 monkey 日志分析
95 | > 将 monkey 日志重定向到文件里
96 | > 在日志内搜索错误关键字,比如 error,anr,crash,exception
97 | > 如果发现错误,结合上下文分析如何产生
98 | > 可以通过种子数复现问题
99 | > 可以用 adb bugreport 生成测试报告查看相关信息
100 |
101 | ## 崩溃有可能的原因
102 |
103 | > 内存泄露、内存溢出、程序代码逻辑错误、设备兼容性问题
104 |
105 | ## app 性能怎么测的
106 |
107 | > 使用 solopi 和性能狗,主要使用 solopi
108 | > 先下载安装 solopi
109 | > 使用 adb tcpip 命令开放端口
110 | > 选择要测的软件
111 | > 勾选要测试的指标:cpu、内存、电量、网络、温度
112 | > 开启监控
113 | > 按常规操作使用软件
114 | > 检查 solopi 生成的指标数据
115 | >
116 | > > 应用程序 cpu 和内存占比在 20% 以下
117 | > > fps 30-60
118 | > > 流量与实际使用流量相近
119 | > > 电量使用稳定,没有过多耗电
120 |
121 | ## Ios 和 Android 区别
122 |
123 | > 开发语言不一样
124 | > 机制不同,ios 是沙盒机制,Android 是虚拟机机制
125 | > Ios 使用伪后台,Android 使用真后台
126 | > 分辨率不同
127 | > 消息推送不同
128 | >
129 | > > Android 需要在 app 里实现推送,或接入第三方 sdk 实现推送【友盟】
130 | > > Ios 使用官方推送服务
131 | >
132 | > Android 默认有三个虚拟按键,ios 只有一个
133 | > Android 和 ios 程序上架方式不同
134 | >
135 | > > Android 需要在各大应用商店上架
136 | > > ios 在 AppStore 上架
137 |
138 | ## app 和 web 区别
139 |
140 | > 架构不同,app 是 C/S 架构,web 是 B/S 架构
141 | > Web 的客户端性能只需要考虑响应时间,app 还有考虑电量内存 cpu 使用情况
142 | > Web 考虑不同浏览器内核和分辨率,app 考虑不同手机品牌、操作系统、版本、分辨率
143 | > app 还要考虑专项测试【中断事件、网络、安装卸载更新、前后台横竖屏切换、权限等】,web 考虑非功能
144 |
145 | ## 怎么测埋点
146 |
147 | > 有两种方式
148 | > 查看客户端埋点日志,安卓可以使用 adb shell logcat,ios 使用 Xcode
149 | > 使用第三方平台进行埋点管理,神测平台
150 | >
151 | > > 输入要测试的埋点名称
152 | > > 点击刷新
153 | >
154 | > 主要测试有没有漏埋点,埋点事件名称和 id 是否准确,埋点数据是否准确,埋点记录的频率是否准确,数据分析统计结果是否准确
155 |
156 | ## 小程序怎么测的
157 |
158 | > 使用真机或微信开发者工具
159 | > 考虑功能是否与需求一致、业务逻辑、数据交互
160 | > 对小程序入口检测:搜索、扫二维码、链接分享
161 | > 授权状态:已授权、未授权、授权后取消
162 | > 兼容性:不同系统、不同系统版本、不同微信版本、不同分辨率
163 | > 缓存:清除缓存
164 | > 网络:弱网、断网
165 | > 安全:敏感数据加密
166 | > 性能:cpu、内存、耗电量、帧率、网络【开发调试 -> 性能监控面板】
167 |
168 | ## app 内存泄漏怎么测的
169 |
170 | > 使用 Android studio 中的 monitor 工具【profiler】
171 | > 下载安装 Android studio
172 | > 配置 androidSDK
173 | > 连接手机打开 usb 调试
174 | > 打开想测试的 app
175 | > 打开 profiler
176 | > 选择要测试的 app
177 | > 正常操作 app
178 | > 导出内存相关分析结果
179 | > 如果结果中包含 leaks 相关数据,则 app 存在内存泄漏
180 | > 可以通过 leaks 定位到代码块,提交给开发修复
181 |
--------------------------------------------------------------------------------
/02_网络基础.md:
--------------------------------------------------------------------------------
1 | # 网络基础
2 |
3 | ## 1.七层架构与四层架构
4 |
5 | | 七层架构 | 四层架构 | 对应网络协议 |
6 | | ---------- | ---------- | ----------------------- |
7 | | 应用层 | 应用层 | HTTP、TFTP、FTP、SMTP |
8 | | 表示层 | | Telnet |
9 | | 会话层 | | SMTP、DNS |
10 | | 传输层 | 传输层 | TCP、UDP |
11 | | 网络层 | 网络层 | IP、ICMP、ARP、UUCP |
12 | | 数据链路层 | 数据链路层 | FDDI、Ethernet |
13 | | 物理层 | | IEEE 802.1A、IEEE 802.2 |
14 |
15 | ## 2.端口
16 |
17 | 知名端口号:0-1023
18 | 动态端口号:1024-65535
19 |
20 | | 端口 | 备注 |
21 | | ---- | ------------ |
22 | | 80 | HTTP |
23 | | 443 | HTTPS |
24 | | 3306 | MYSQL |
25 | | 21 | FTP |
26 | | 22 | SSH |
27 | | 53 | DNS |
28 | | 25 | SMTP |
29 | | 1521 | ORADE 数据库 |
30 | | 23 | telnet |
31 |
32 | ## 3.TCP 与 UDP
33 |
34 | | | UDP | TCP |
35 | | -------- | -------------------------- | ------------------------ |
36 | | 连接 | 无连接 | 面向连接 |
37 | | 速度 | 无需建立连接,速度较快 | 常需要建立连接,速度较快 |
38 | | 目的主机 | 一对一,一对多 | 仅能一对一 |
39 | | 带宽 | UDP 报头较短,消耗带宽更少 | 消耗更多带宽 |
40 | | 消息边界 | 有 | 无 |
41 | | 可靠性 | 低 | 高 |
42 | | 顺序 | 无序 | 有序 |
43 |
44 | **三次握手四次挥手过程**
45 |
46 | ## URL
47 |
48 | 组成:协议+域名+资源路径
49 |
50 | ## HTTP 请求报文
51 |
52 | get:
53 | 请求行 ----- 请求方式、请求路径、协议版本
54 | 请求头
55 | 空行
56 |
57 | post:
58 | 请求行
59 | 请求头
60 | 空行
61 | 请求体
62 |
63 | 一个 HTTP 请求报文可以由请求行、请求头、空行和请求体 4 个部分组成。
64 | 请求行是由三部分组成:
65 |
66 | 1. 请求方式
67 | 2. 请求资源路径
68 | 3. HTTP 协议版本
69 |
70 | GET 方式的请求报文没有请求体,只有请求行、请求头、空行组成。
71 | 请求数据,参数长度有限制,参数在 url
72 | POST 方式的请求报文可以有请求行、请求头、空行、请求体四部分组成,
73 | 提交数据,参数长度没有限制,参数在请求体
74 |
75 | DELECT 删除
76 | PUT 修改
77 |
78 | ## 请求状态码
79 |
80 | | 状态类型 | 状态码和状态信息 | 含义 |
81 | | :------------- | :--------------- | :----------------------------------------------------------------------------------------------------------------------------------------------- |
82 | | 1xx 信息 | 100 | 服务器收到了客户端的请求行和头部信息,告诉客户端继续发送数据部分,客户端通常需要先发送 Expect: 100-continue 头部字段告诉服务器自己还有数据要发送 |
83 | | 2xx 成功 | 200 | 请求成功 |
84 | | 3xx 重定向 | 301 | 资源被转移了,请求将被重定向 |
85 | | | 302 | 通知客户端资源能在别的地方找到,但需要使用 GET 方法来获得它 |
86 | | | 304 | 表示被申请的资源没有更新,和之前获得的相同 |
87 | | | 307 | 通知客户端资源能在其他地方找到,与 302 不同的是,客户端可以使用和原始请求相同的请求方法来访问目标资源 |
88 | | 4xx 客户端错误 | 400 | 通用客户请求错误 |
89 | | | 401 | 请求需要认证信息 |
90 | | | 403 | 访问被服务器禁止,通常是由于客户端没有权限访问该资源 |
91 | | | 404 | 资源没有找到 |
92 | | | 407 | 客户端需要先获得代理服务器的认证 |
93 | | 5xx 服务器错误 | 500 | 通用服务器错误 |
94 | | | 503 | 暂时无法访问服务器 |
95 |
96 | ## 请求头
97 |
98 | | Host: | 请求的目标域名 | \* | |
99 | | :--------------- | :--------------------------------------------- | :-- | :-------- |
100 | | Referer : | 防盗链 | | 请求 |
101 | | User-Agent: | 客户端信息 | \* | 请求 |
102 | | Accept: | 客户端期望接受的数据类型 | | 请求 |
103 | | Accept-Encoding: | 客户端期望接受的压缩格式 | | 请求 |
104 | | Accept-Language: | 客户端可以接受的语言 | | 请求 |
105 | | Connection: | 如果值是 keep-alive 就是可以支持 TCP 长连接 | | 请求/响应 |
106 | | Connect-Type: | 标明请求体或响应体的数据类型 | \* | 请求/响应 |
107 | | Content-Length: | 请求体响应体内数据长度 | \* | 请求/响应 |
108 | | Date: | 服务器返回数据的时间 | | 响应 |
109 | | Cache-Contorl: | 缓存方式 | | |
110 | | Last-Modified: | 服务器资源最后一次修改的时间 | \* | |
111 | | Cookie: | 表示用户身份信息 | \* | 请求 |
112 | | Set-Cookie: | 服务器返回客户端之后请求需要携带的 Cookie 信息 | \* | 响应 |
113 |
--------------------------------------------------------------------------------
/03_数据库.md:
--------------------------------------------------------------------------------
1 | # 数据库基础
2 |
3 | 登录数据库: mysql-uroot -p
4 | 退出数据库: quit 或者 exit 或者 ctrl + d
5 | 创建数据库: create database 数据库名 charset=utf8 collate utf8_bin
6 | 使用数据库: use 数据库名:
7 | 删除数据库: drop database 数据库名;
8 | 创建表: create table 表名 (字段名字段类型约束 (试情况添加),…);
9 | 修改表 - 添加字段: alter table 表名 add 字段名字段类型约束
10 | 修改表修改字段类型: alter table 表名 modify 字段名字段类型约束
11 | 修改表修改字段名和字段类型: alter table 表名 change 原字段名新字段名字段类型约束
12 | 修改表 - 删除字段: alter table 表名 drop 字段名
13 | 删除表: drop table 表名;
14 | 查询数据: select \* from 表名; 或者 select 列 1, 列 2,… From 表名
15 | 插入数据: insert into 表名 values (..) 或者 insert into 表名例 1…) values (值 1…
16 | 修改数据: update 表名 set 列 1=值 1, 列 2=值 2… Where 条件
17 | 删除数据: delete from 表名 where 条件
18 |
19 | as 关键字可以给表中字段或者表名起别名
20 | distinct 关键字可以去除重复数据行。
21 |
22 | 常见的比较运算符有 > , < , > =, < =, !=
23 | 逻辑运算符 and 表示多个条件同时成立则为真,or 表示多个条件有一个成立则为真,not 表示对条件取反
24 |
25 | like 和% 结合使用表示任意多个任意字符,like 和 \_ 结合使用表示一个任意字符
26 |
27 | between-and 限制连续性范围 in 限制非连续性范围
28 |
29 | 判断为空使用: is null 判断非空使用: is not null
30 |
31 | 1. 排序使用 order by 关键字
32 | 2. Asc 表示升序
33 | 3. Desc 表示降序
34 |
35 | 使用 limit 关键字可以限制数据显示数量,通过 limit 关键可以完成分页查询
36 | limit 关键字后面的第一个参数是开始行索引 (默认是 0,不写就是 0),第二个参数是查询条数
37 |
38 | ## 聚合函数
39 |
40 | count (col): 表示求指定列的总行数
41 | max (col): 表示求指定列的最大值
42 | min (col): 表示求指定列的最小值
43 | sum (col): 表示求指定列的和
44 | avg (col): 表示求指定列的平均值
45 |
46 | Ifnull 函数: 表示判断指定字段的值是否为 null,如果为空使用自己提供的值。
47 |
48 | ## 分组查询
49 |
50 | group by 根据指定的一个或者多个字段对数据进行分组
51 | group_concat (字段名) 函数是统计每个分组指定字段的信息集合
52 | 聚合函数在和 group by 结合使用时, 聚合函数统计和计算的是每个分组的数据
53 | having 是对分组数据进行条件过滤
54 | with rollup 在最后记录后面新增一行,显示 select 查询时聚合函数的统计和计算结果
55 |
56 | ## 连接查询
57 |
58 | 内连接使用 inner join .. On .., on 表示两个表的连接查询条件
59 | 内连接根据连接查询条件取出两个表的 “交集”
60 |
61 | 左连接使用 left join .. On .., on 表示两个表的连接查询条件
62 | 左连接以左表为主根据条件查询右表数据,右表数据不存在使用 null 值填充。
63 |
64 | 右连接使用 right join .. On .., on 表示两个表的连接查询条件
65 | 右连接以右表为主根据条件查询左表数据,左表数据不存在使用 null 值填充。
66 |
67 | 自连接查询就是把一张表模拟成左右两张表,然后进行连表查询。
68 | 自连接就是一种特殊的连接方式,连接的表还是本身这张表
69 |
70 | ## 子查询
71 |
72 | 在一个 select 语句中, 嵌入了另一个 select 语句, 那么被嵌入的 select 语句称之为子查询语句,外部那个 select 语句则称为主查询.
73 |
74 | 1. 子查询是嵌入到主查询中
75 | 2. 子查询是辅助主查询的, 要么充当条件, 要么充当数据源
76 | 3. 子查询是可以独立存在的语句, 是一条完整的 select 语句
77 |
78 | 子查询是一个完整的 SQL 语句,子查询被嵌入到一对小括号里面
79 |
80 | ## 范式
81 |
82 | 第一范式(1 NF): 强调的是列的原子性,即列不能够再分成其他几列。
83 | 第二范式(2 NF): 满足 1 NF,另外包含两部分内容,一是表必须有一个主键;二是非主键字段必须完全依赖于主键,而不能只依赖于主键的一部分。
84 | 第三范式(3 NF): 满足 2 NF,另外非主键列必须直接依赖于主键,不能存在传递依赖。即不能存在:非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的情况。
85 |
86 | 范式就是设计数据库的一些通用规范。
87 | 1 NF 强调字段是最小单元,不可再分
88 | 2 NF 强调在 1 NF 基础上必须要有主键和非主键字段必须完全依赖于主键,也就是说不能部分依赖
89 | 3 NF 强调在 2 NF 基础上非主键字段必须直接依赖于主键,也就是说不能传递依赖 (间接依赖)。
90 |
91 | ## E-R 模型
92 |
93 | E-R 模型由实体、属性、实体之间的关系构成,主要用来描述数据库中表结构。
94 | 开发流程是先画出 E-R 模型,然后根据三范式设计数据库中的表结构
95 |
96 | ## 外键
97 |
98 | 外键约束: 对外键字段的值进行更新和插入时会和引用表中字段的数据进行验证,数据如果不合法则更新和插入会失败,保证数据的有效性
99 |
100 | ```mysql
101 | -- 为cls_id字段添加外键约束
102 | alter table students add foreign key(cls_id) references classes(id);
103 | ```
104 |
105 | ```mysql
106 | -- 需要先获取外键约束名称,该名称系统会自动生成,可以通过查看表创建语句来获取名称
107 | show create table teacher;
108 |
109 | -- 获取名称之后就可以根据名称来删除外键约束
110 | alter table teacher drop foreign key 外键名;
111 | ```
112 |
113 | 添加外键约束: alter table 从表 add foreign key (外键字段) references 主表 (主键字段);
114 | 删除外键约束: alter table 表名 drop foreign key 外键名;
115 |
116 | ## 索引
117 |
118 | #索引
119 |
120 | ```mysql
121 | -- 查看已有索引
122 | show index from 表名;
123 |
124 | -- 创建索引
125 | alter table 表名 add index 索引名[可选](列名);
126 |
127 | -- 删除索引
128 | alter table 表名 drop index 索引名;
129 | ```
130 |
131 | ```mysql
132 | -- 开启运行时间监测:
133 | set profiling=1;
134 | -- 查找第1万条数据ha-99999
135 | select * from test_index where title='ha-99999';
136 | -- 查看执行的时间:
137 | show profiles;
138 | -- 给title字段创建索引:
139 | alter table test_index add index (title);
140 | -- 再次执行查询语句
141 | select * from test_index where title='ha-99999';
142 | -- 再次查看执行的时间
143 | show profiles;
144 | ```
145 |
146 | **_联合索引_**
147 |
148 | ```mysql
149 | -- 创建teacher表
150 | create table teacher
151 | (
152 | id int not null primary key auto_increment,
153 | name varchar~~(~~10),
154 | age int
155 | );
156 | -- 创建联合索引
157 | alter table teacher add index (name,age);
158 | ```
159 |
160 | 联合索引的好处:
161 | 减少磁盘空间开销,因为每创建一个索引,其实就是创建了一个索引文件,那么会增加磁盘空间的开销。
162 |
163 | 索引是加快数据库的查询速度的一种手段
164 | 创建索引使用: alter table 表名 add index 索引名 [可选] (字段名, xxx);
165 | 删除索引使用: alter table 表名 drop index 索引名
166 |
167 | ## 数据库备份
168 |
169 | ### 备份数据库
170 |
171 | ```shell
172 | mysqldump -u用户名 -p密码 --databases 数据库1 数据库2 > xxx.sql
173 | ```
174 |
175 | 常见选项:
176 |
177 | -u: 用户名
178 | -p: 密码
179 | -P: 端口号,不写默认 3306
180 | --all-databases, -A:备份所有数据库
181 | --databases, -B: 用于备份多个数据库,如果没有该选项,mysqldump 把第一个名字参数作为数据库名,后面的作为表名。使用该选项,mysqldump 把每个名字都当作为数据库名。
182 | -d: 只导出数据库的表结构
183 | -t: 只导出数据库的数据
184 | --quick, -q:快速导出
185 | --xml, -X:导出为 xml 文件
186 |
187 | ```shell
188 | mysqldump -uroot -p123456 -A > 0101.sql
189 | ```
190 |
191 | ### 还原数据库
192 |
193 | 1. 系统命令行:
194 |
195 | ```shell
196 | mysqladmin -uroot -p 123456 create db_name
197 |
198 | mysql -uroot -p 123456 db_name < 0101.sql
199 |
200 | -- 注:在导入备份数据库前,db_name如果没有,是需要创建的; 而且与0101.sql中数据库名是一样的才可以 导入。
201 | ```
202 |
203 | 2. Soure 方法
204 |
205 | ```mysql
206 | Mysql > use db
207 | mysql > source 0101. Sql
208 | ```
209 |
210 | ## explain
211 |
212 | ```mysql
213 | -- 实际SQL,查找用户名为Jefabc的员工
214 | select * from emp where name = 'Jefabc';
215 |
216 | -- 查看SQL是否使用索引,前面加上explain即可
217 | explain select * from emp where name = 'Jefabc';
218 | ```
219 |
220 | • EXPLAIN 不会告诉你关于触发器、存储过程的信息或用户自定义函数对查询的影响情况
221 | • EXPLAIN 不考虑各种 Cache
222 | • EXPLAIN 不能显示 MySQL 在执行查询时所作的优化工作
223 | • 部分统计信息是估算的,并非精确值
224 | • Explain 只能解释 SELECT 操作,其他操作要重写为 SELECT 后查看执行计划
225 |
226 | ## 存储过程
227 |
228 | 思考:如何快速构造 1000 条数据到数据库。
229 | 存储过程是一组预先编写好的 SQL 语句集合, 它们按特定的顺序依次执行, 完成各种数据库操作的功能, 并返回执行结果给用户
230 |
231 | ```mysql
232 | Create PROCEDURE test ()
233 | begin
234 | DECLARE i int default 1; #定义计数器
235 | while i <=10
236 | do
237 | insert into students values (0,'小明','男','一班');
238 | set i = i+1; #每执行一次计数器加1
239 | end while;
240 | end;
241 | call test ();
242 | ```
243 |
244 | ```mysql
245 | create PROCEDURE test 1 ()
246 | begin
247 | DECLARE i int default 1; #定义计数器
248 | DECLARE index_i VARCHAR (6) DEFAULT "0"; #定义名字字符串后缀
249 | while i <=10
250 | do
251 | set index_i=CONVERT (i, char (6)); #将计数器值转换为字符串
252 | insert into student values (0,CONCAT ('小明', index_i),'男','一班'); #进行字符串拼接并插入数据
253 | set i = i+1;
254 | end while;
255 | end;
256 | call test 1 ();
257 |
258 | ```
259 |
--------------------------------------------------------------------------------
/04_软件测试入门.md:
--------------------------------------------------------------------------------
1 | # 软件测试入门
2 |
3 | ## 软件测试理论
4 |
5 | ### 什么是软件测试
6 |
7 | 在规定条件下对程序进行操作, 从而发现错误, 对软件质量进行评估的一个过程.
8 |
9 | ### 软件测试的目的
10 |
11 | 是想以最少的人力,物力和时间找出软件中潜在的各种错误与缺陷,通过修正各种错误和缺陷提高软件质量,回避软件发布后由于潜在的软件缺陷和错误造成的隐患以及带来的商业风险。
12 |
13 | ### 软件测试的定义
14 |
15 | 使用人工或自动手段来运行或测试某个系统的过程, 其目的在于检验它是否满足规定的需求或是弄清预期结果和实际结果之间的差别
16 |
17 | ## 公司分类
18 |
19 | - 自研公司 (有公司主营自主研发产品) 需求:公司自己制定的
20 | - 外包公司
21 | - 项目外包 (产品是客户的,给客户研发定制产品) 需求:客户
22 | - 项目组:公司内部
23 | - 人力外包 (产品是客户的,给客户研发定制产品) 需求:客户
24 | - 项目组:客户的公司
25 |
26 | ## 测试分类
27 |
28 | - 软件测试
29 | - 硬件测试
30 | - 嵌入式测试
31 | - 游戏测试
32 |
33 | 嵌入式测试:
34 |
35 | - 方案公司
36 | - 项目组客户:集成公司客户
37 | - 集成公司
38 | - 项目组客户:客户
39 | - 测试
40 |
41 | ## 常见公司项目组,组织架构
42 |
43 | 软件项目组
44 |
45 | - 项目经理 (1)
46 | - 产品
47 | - 研发部
48 | - 技术总监/经理/主管
49 | - 开发
50 | - 测试部
51 | - 测试总监/经理/主管
52 | - 测试
53 | - A 项目组
54 | - 项目经理
55 | - 产品经理
56 | - 开发
57 | - 测试
58 | - B 项目组
59 |
60 | 项目经理(1 个):掌控整个项目(需求,进度,人员)
61 | 产品( 1~2 个): 确定产品需求,产品经理会将需求转化为《产品原型图》, 产品需求规格书(需求文档) (墨刀, 蓝湖, Axure)
62 | UI 设计师(女)1~2 个:产品原型图,ui 设计
63 | 前端工程师(开发):前端页面 Web(1 ~ 2 人),Android(1 ~ 2 人),IOS(1 ~ 2 人),小程序/H 5 (1~2)
64 | 后端工程师(开发):数据接口 (3~4 人)
65 | 测试工程师(2~3 人):软件质量一般和开发比例 1:3, 2:5 , 1:5(工资高,成长快)
66 | 运维工程师(1 人):上线,维护,服务器
67 | 研发部:技术总监(经理)(主管)
68 | 测试部:测试总监(经理)(主管)
69 | 财务,人事,市场,硬件,QC,运营(推广,后期数据统计,转化率)
70 |
71 | ## 软件开发模型
72 |
73 | - 瀑布模型
74 | - 快速原型模型
75 | - 增量模型 (迭代模型)
76 | - 螺旋模型
77 |
78 | ## 1. 瀑布模型
79 |
80 | 瀑布模型将软件生命周期划分为制定计划、需求分析、系统设计、程序编写、软件测试和运行维护等六个基本活动,并且规定了它们自上而下、相互衔接的固定次序,如同瀑布流水,逐级下落。
81 |
82 | ### 瀑布模型核心思想
83 |
84 | 在瀑布模型中,软件开发的各项活动严格按照线性方式进行,当前活动接受上一项活动的工作结果,实施完成所需的工作内容。当前活动的工作结果需要进行验证,如果验证通过,则该结果作为下一项活动的输入,继续进行下一项活动,否则返回修改
85 |
86 | ### 优缺点
87 |
88 | 优点:
89 |
90 | 1. 为项目提供了按阶段划分的检查点, 软件开发的每个阶段都很清晰明了
91 | 2. 当前阶段完成后, 只要去关注后续阶段
92 | 3. 可在迭代模型中每轮迭代很类似于一个小的瀑布模型
93 | 4. 它提供了一个模版, 这个模版使得分析、设计、编码、测试可以在该模版下有一个共同的指导
94 |
95 | 缺点:
96 |
97 | 1. 各个阶段的划分完全固定,阶段之间产生大量的文档,极大地增加了工作量
98 | 2. . 由于开发模型是线性的,用户只有等到整个过程的末期才能见到开发成果,从而增加了开发风险
99 | 3. 突出缺点是不适应用户需求的变化
100 | 4. 软件的实际情况必须到项目开发的后期客户才能看到,这要求客户有足够的耐心
101 |
102 | ### 使用范围
103 |
104 | 用户的需求非常清楚全面,且在开发过程中没有或很少变化;开发工作对用户参与的要求很低。
105 |
106 | ## 2. 快速原型模型
107 |
108 | 快速原型模型的第一步是建造一个快速原型,实现客户或未来的用户与系统的交互,用户或客户对原型进行评价,进一步细化待开发软件的需求。通过逐步调整原型使其满足客户的要求,开发人员可以确定客户的真正需求是什么;第二步则在第一步的基础上开发客户满意的软件产品。
109 |
110 | ### 核心思想
111 |
112 | 快速原型是利用原型辅助软件开发的一种新思想。经过简单快速分析,快速实现一个原型,用户与开发者在试用原型过程中加强通信与反馈,通过反复评价和改进原型,减少误解,弥补漏洞,适应变化,最终提高软件质量
113 |
114 | ### 优缺点
115 |
116 | 优点:
117 |
118 | - 克服瀑布模型的缺点, 适应需求的变化, 能够开发出更加让用户更满意的需求
119 |
120 | 缺点:
121 |
122 | - 所选用的开发技术和工具不一定符合主流的发展;
123 | - 快速建立起来的系统结构加上连续的修改可能会导致产品质量低下。
124 | - 使用这个模型的前提是要有一个展示性的产品原型,因此在一定程度上可能会限制开发人员的创新。
125 |
126 | ### 使用范围
127 |
128 | - 不适合大型项目的研发
129 | - 对所开发的领域比较熟悉而且有快速的原型开发工具
130 |
131 | ## 3.增量(迭代)模型
132 |
133 | ### 介绍
134 |
135 | 增量模型(迭代模型),是把待开发的软件系统模块化,将每个模块作为一个增量组件,从而分批次地分析、设计、编码和测试这些增量组件。运用增量模型的软件开发过程是递增式的过程。相对于瀑布模型而言,采用增量模型进行开发,开发人员不需要一次性地把整个软件产品提交给用户,而是可以分批次进行提交
136 |
137 | ### 基本思想
138 |
139 | 迭代模型在各个阶段并不交付一个可运行的完整产品,而是交付满足客户需求的一个子集的可运行产品。整个产品被分解成若干个构件,开发人员逐个构件地交付产品,这样做的好处是软件开发可以较好地适应变化,客户可以不断地看到所开发的软件,从而降低开发风险
140 |
141 | ### 优缺点
142 |
143 | 优点:
144 |
145 | - 将待开发的软件系统模块化,可以分批次地提交软件产品,使用户可以及时了解软件项目的进展
146 | - 以组件为单位进行开发降低了软件开发的风险。一个开发周期内的错误不会影响到整个软件系统。
147 | - 开发顺序灵活。开发人员可以对组件的实现顺序进行优先级排序,先完成需求稳定的核心组件。当组件的优先级发生变化时,还能及时地对实现顺序进行调整。
148 |
149 | 缺点:
150 |
151 | - 要求待开发的软件能给进行增量式的开发, 否则会很麻烦
152 | - 在软件开发过程中需求变化是不可避免的, 增量模型的灵活性可以使其适应这种变化的能力大大优于瀑布模型和快速原型模型,但也很容易退化为边做边改模型,从而是软件过程的控制失去整体性.
153 |
154 | ### 使用场景
155 |
156 | 进行已有产品升级或新版本开发
157 |
158 | ## 4.螺旋模型
159 |
160 | 螺旋模型沿着螺线进行若干次迭代,四个象限代表了以下活动:
161 | (1) 制定计划:确定软件目标,选定实施方案,弄清项目开发的限制条件;
162 | (2) 风险分析:分析评估所选方案,考虑如何识别和消除风险;
163 | (3) 实施工程:实施软件开发和验证;
164 | (4) 客户评估:评价开发工作,提出修正建议,制定下一步计划。
165 | 螺旋模型由风险驱动,强调可选方案和约束条件从而支持软件的重用,有助于将软件质量作为特殊目标融入产品开发之中。
166 |
167 | ### 优缺点
168 |
169 | 优点:
170 |
171 | - 设计灵活可以在项目各个阶段进行变更
172 | - 风险驱动, 每个项目上线前都要进行风险分析
173 |
174 | 缺点:
175 |
176 | - 螺旋模型强调风险分析, 需要相当丰富的风险评估经验和专业知识, 在风险较大的项目开发中,如果未能够及时标识风险,势必造成重大损失;
177 | - 如果执行风险分析将大大影响项目的利润,那么进行风险分析毫无意义,
178 |
179 | ### 使用场景
180 |
181 | 适合使用大规模,大型的软件项目
182 |
183 | ## 测试模型
184 |
185 | ### V 模型
186 |
187 | V 模型和瀑布模型有一些共同的特性,V 模型中的过程从左到右,描述了基本的开发过程和测试行为
188 |
189 | #### 单元测试
190 |
191 | 是模块测试,验证软件的基本组成单位的正确性,是白盒测试
192 | (代码层测试,逻辑覆盖)(代码中添加 unittest 模块,代码扫描工具)
193 |
194 | #### 集成测试
195 |
196 | 是模块间的测试,测试接口
197 | (软件各模块之间的接口和软件与硬件之间的接口)是否正确,是灰盒测试(白盒和黑盒结合)
198 |
199 | #### 系统测试
200 |
201 | 系统测试包括:冒烟测试、系统测试、回归测试 ^d0091e
202 |
203 | ##### 冒烟测试
204 |
205 | 主干流程测试,确认软件的基本功能正常,可以进行后续的测试工作
206 |
207 | ##### 系统测试
208 |
209 | 是检测系统的功能、质量、性能能否满足系统的要求,包括
210 | 功能
211 | 界面
212 | 易用性
213 | 安全性:数据传输安全性、用户安全性、服务器安全性
214 | 兼容性:不同设备、不同环境
215 | 性能:服务端性能、客户端性能
216 | 等等,是黑盒测试 ^04d731
217 |
218 | ##### 回归测试
219 |
220 | 开发修改了旧代码之后重新进行测试 (需求改变了,修改错误之后),确认修改后的代码没有引入新的错误或导致其他代码产生新的错误。分为
221 | 功能回归: 不只验证当前出问题的功能是否修复,还要验证功能相关模块是否有新的问题;
222 | 系统回归(测试 2~3 轮): 包括功能回归测试,当系统测试完成后,针对之前经常出问题的功能模块和系统流程进行测试,避免遗漏
223 |
224 | #### 验收测试
225 |
226 | 是确保软件的实现能否满足用户的需求或合同的要求
227 | (客户,测试,第三方)
228 |
229 | #### 优缺点
230 |
231 | 优点:
232 |
233 | - 每一个阶段都清晰明了、便于控制开发的每一个过程
234 | - 既包含单元测试又包含系统测试
235 |
236 | 缺点:
237 |
238 | - 测试介入的较晚, 对于前期的一些缺陷无从发现和修改
239 | - 测试和开发串行
240 |
241 | ### w 模型
242 |
243 | 优点
244 | 测试伴随软件的整个生命周期, 例如, 在需求分析结束后就可以进行需求分析测试
245 | 测试与开发是并行独立进行
246 | 缺点
247 | 对需求和测试技术要求高
248 | 适用于大中型企业
249 |
250 | ### h 模型
251 |
252 | 优点
253 | 开发的 H 模型揭示了软件测试除测试执行外,还有很多工作;
254 | 软件测试完全独立,贯穿整个生命周期,且与其他流程并发进行;
255 | 软件测试活动可以尽早准备、尽早执行,具有很强的灵活性;
256 | 缺点:
257 | 管理型要求高:由于模型很灵活,必须要定义清晰的规则和管理制度,否则测试过程将非常难以管理和控制;
258 | 技能要求高:H 模型要求能够很好的定义每个迭代的规模,不能太大也不能太小;
259 | 测试就绪点分析困难:测试很多时候,你并不知道测试准备到什么时候是合适的,就绪点在哪里,就绪点的标准是什么,这就对后续的测试执行的启动带来很大困难;
260 |
261 | ## 软件测试分类
262 |
263 | ### 按阶段划分
264 |
265 | #### 单元测试
266 |
267 | 由开发工程师进行测试,代码走查、评审、代码扫描
268 | 测试方法:白盒测试(语句覆盖、判定覆盖、条件覆盖、判定条件覆盖、条件组合覆盖、路径覆盖)
269 | 测试依据:代码和注释 + 设计文档
270 |
271 | #### 集成测试
272 |
273 | 接口测试
274 | 在单元测试之后,冒烟测试之前
275 | 测试方法:灰盒测试
276 | 测试依据:单元测试模块 + 接口文档
277 |
278 | #### 系统测试
279 |
280 | 对整个系统进行测试,包括冒烟测试、系统测试、回归测试
281 | 测试方法:黑核测试
282 | 测试依据:需求文档
283 |
284 | ### 按是否覆盖源码划分
285 |
286 | #### 黑盒测试
287 |
288 | 功能测试
289 | 性能测试
290 |
291 | #### 白盒测试
292 |
293 | 测试代码
294 |
295 | #### 灰盒测试
296 |
297 | 测试接口
298 |
299 | ### 按是否执行程序划分
300 |
301 | #### 静态测试
302 |
303 | 白盒测试
304 | 需求文档、设计文档、源码
305 |
306 | #### 动态测试
307 |
308 | 灰盒测试、黑盒测试
309 |
310 | ### 按是否自动化划分
311 |
312 | #### 手工测试
313 |
314 | 优点:探索性测试、发散性思维
315 | 缺点:效率慢,量大易错
316 |
317 | #### 自动化测试
318 |
319 | 在性能测试之后,依靠脚本或者工具
320 | 优点:效率高
321 | 缺点:无法替代探索性测试,只能完成既定代码和流程,对测试人员技术要求高,维护成本高
322 |
323 | 测试步骤:
324 |
325 | 1. 完成功能测试,版本基本稳定
326 | 2. 根据项目,选择合适工具
327 | 3. 提取手工测试的测试用例转化为自动化测试用例
328 | 4. 通过工具、代码实现测试
329 | 5. 生成测试报告
330 | 6. 持续改进优化
331 |
332 | ### 其他 \*
333 |
334 | #### 冒烟测试
335 |
336 | #### 回归测试
337 |
338 | #### 随机测试
339 |
340 | 随机抽查,没法保证准确性
341 |
342 | #### 验收测试
343 |
344 | 部署软件之前的最后一个测试,在系统测试之后
345 | 按照需求文档进行验收
346 | 验收方:用户/需求方
347 | 验收依据:用户需求,验收标准
348 | 测试方法:白盒、黑盒、灰盒,以黑盒为主
349 | 测试内容:功能测试为主
350 |
351 | 验收测试分为 α 测试与 β 测试:
352 |
353 | ##### α 测试
354 |
355 | 由内部用户在开发环境下进行的测试
356 |
357 | ##### β 测试
358 |
359 | ##### 区别
360 |
361 | 测试场所不同:α 测试在开发方场所,β 测试在用户场所
362 | α 测试环境受开发方控制,用户数量少,时间集中,β 测试环境不受开发方控制,用户数量较多,时间不集中
363 | α 测试比 β 测试早
364 |
--------------------------------------------------------------------------------