一、基本概念
1. 什么是软件测试
软件测试是针对不同业务设计不用的测试用例发现程序/软件错误的过程 ,提高软件的质量和可靠性,确保软件在交付给最终用户之前,能够满足预定的质量标准和需求。Quality Assurances
2. 一个bug是前端还是后端
前端无数据展示:这时候直接查看调用接口,看接口返回状态即可
(1)状态正常有数据返回并且返回数据符合预期则为前端BUG
(2)状态正常预期应有数据返回但接口无数据返回则为后端BUG
(3)状态异常根据返回的状态码区分到底是哪端的BUG
-
- 500 后端接口异常
- 502|504|一般为服务器异常,所以既不是前端也不是后端,是服务器的锅
- 404 有可能为服务器异常,也有可能为后端异常,首先排查url地址是否正确,其次排查服务器运行是否正常,如以上都正常则大概率为后端BUG
- 400 一般为前端BUG
(4)前端有数据显示但不符合预期:
查看调用接口返回数据,对照api文档(如有)核实对应字段的值,查看字段值是否符合预期,如果符合,前端BUG,如不符合,排查数据库对应字段是否与后端返回数据一致,不一致则说明为后端BUG,一致则需要继续排查到底为何连数据库的数据都不符合预期,是人为修改,还是程序执行中被修改(后端bug)。
3. 灰度
灰度测试就是指如果软件要在不久的将来推出一个全新的功能,或者做一次比较重大的改版的话,要先进行一个小范围的尝试工作,然后再慢慢放量,直到这个全新的功能覆盖到所有的系统用户,也就是说在新功能上线内测。
日常测试过程中,涉及到的“灰度”有两种含义:
(1) 业务灰: 需求上线后,通过灰度配置,来实现业务推广的灰度;
(2) 技术灰度: 主要是RD上线过程中,通过控制上线的机器数量,来实现技术上的灰度; (日常的一些组件版本升级,常采用技术灰度上线)
QA:灰度内逻辑验证,灰度外逻辑回归,灰度开关功能验证,灰度配置的异常性验证
前置阶段:需求方案评审,关注是否涉及到灰度方案;技术方案评审,关注灰庭计划的实现策略(例:灰度通过什么控制实现?) ;测试用例设计,case需要覆盖灰度开关
测试阶段:验证灰度开关功能是否ok;覆普灰度内场景、灰度外场景逻辑;灰度方案若通过mcc等配置实现,测试阶段需覆盖配置的异常测试,验证系统的健壮性
上线阶段:关注上线checklist中灰度方案的实施计划
4. 分支管理
master分支是git主分支,提供给用户使用的正常版本,日常开发在develop分支
git checkout -b develop master
git checkout master
//分支切换
git merge --no-ff develop
//分支合并
默认git执行fast-farward merge,直接将master指向develop,如果使用noff参数,会在master分支上生成新节点,版本演进比较清晰。
feature分支:develop分支分出来的
git checkout -b feature-x develop //创建分支
git checkout develop //分支切换
git merge --no-ff feature-x //分支合并
git branch -d feature-x //删除
release分支:develop分支分出来的,最后需要合并进develop和master
git checkout -b release-1.2 develop //分支发布
git checkout master//master分支合并
git merge --no-ff release-1.2
git tag -a 1.2//打rtag
git checkout develop//develop分支合并
git merge --no-ff release-1.2
git branch -d release-1.2//删除
fixbug分支:master分支分出来的
git checkout -b fixbug-0.1 master//分支发布
git checkout master//master分支合并
git merge --no-ff fixbug-0.1
git tag -a 0.1.1//打rtag
git checkout develop//develop分支合并
git merge --no-ff fixbug-0.1
git branch -d fixbug-0.1//删除
5. 测试环境
(1)dev环境:开发环境, 开发环境数据库一般使用本地数据库,即localhost
(2)泳道环境: 测试环境和生产环境可能有独立部署的数据库服务器,即需要指定具体的ip。所以一般会有数份配置文件来保存不同环境的不同配置信息。
- 开发联调
- QA测试
-
- test环境:功能测试
-
-
- 泳道:feature代码部署到泳道上,交付,QA进行冒烟+线下功能
- 主干:feature分支合并到QA分支,QA部署test环境,rd在test冒烟
-
-
- stage环境:线上数据回归验证
-
-
- 上线代码合并到release,用release发布stage,QA在st验证,打rtag,master上rtag节点带有本次上线最新代码,线上数据回归测试+checklist回归
- RD维护
-
-
- prod环境:RD使用rtag发布线上, 应用上线运行的环境,一般为客户提供的服务器
6. 服务发布
JAR包:使用JAR文件可以将一个Java项目或库打包成一个单独的文件,方便在不同的Java虚拟机(JVM)上运行,并可以轻松地在不同的系统之间共享和部署。
服务发布要先部署jar包
7. B端服务化与接口化
B端服务化和接口化是指在企业级(B端)应用中,将不同功能模块和业务逻辑拆分成独立的服务或接口,以实现更高效、灵活和可扩展的系统架构。
B端服务化:B端服务化是指将一个大型的应用系统拆分成多个独立的服务,每个服务负责完成特定的功能或业务逻辑。这些服务可以独立部署、运行和维护,并通过网络接口进行通信。这种架构的好处是可以提高系统的可维护性和扩展性,不同的团队可以独立开发和维护不同的服务,同时可以更好地应对高并发和大流量的情况。
B端接口化:B端接口化是指将一个系统的功能和服务通过接口暴露给其他系统或应用程序进行调用。这些接口可以是RESTful API、SOAP、gRPC等形式,可以跨语言和跨平台进行通信。接口化可以使不同的系统之间实现松耦合,即使系统的内部实现发生变化,只要接口不变,其他系统的调用不受影响。这样可以实现系统的模块化和复用,提高整体系统的灵活性和可维护性。
综合来说,B端服务化和接口化是企业级应用中常用的架构设计方法,可以使系统更加灵活、高效、可扩展,有助于应对复杂的业务需求和高并发的访问情况。
8. 埋点
埋点是指在软件或应用程序中插入代码或标记,以便收集用户行为和应用程序使用情况的数据。这些代码或标记通常用于跟踪用户在应用程序中的各种操作,例如点击按钮、访问特定页面、触发事件等。埋点是数据采集的一种方法,可以帮助开发者或运营团队了解用户的行为模式、使用习惯和应用程序的性能,从而进行数据分析、优化和决策。
埋点通常涵盖以下几个方面的数据采集:
- 页面浏览:记录用户访问的页面和页面停留时间,了解用户浏览路径和热门页面。
- 事件触发:记录用户在应用程序中触发的特定事件,例如点击按钮、提交表单等。
- 错误追踪:记录应用程序发生的错误和异常,帮助开发者及时发现和解决问题。
- 性能监控:记录应用程序的性能指标,例如加载时间、响应时间等,以便优化用户体验。
9. 服务端和web端
首先,服务端是整个系统的核心,所有的业务逻辑都由它来处理。服务端的主要任务是处理用户请求、连接数据库和资源管理。它必须能够快速响应用户请求,并能够在最短的时间内处理请求,确保系统的高效运行。服务端通常采用Java、Python、Ruby等语言来开发,有时会涉及到Linux、Redis、MySQL等技术。
相比之下,web端主要承担着数据交互和前端展示等任务。它必须在服务端的处理之后将数据展示给用户,并能够快速响应用户的操作。web端通常采用HTML、CSS、JavaScript等技术进行开发,能够进行行云流水的页面展示和用户交互。
其次,服务端和web端之间也有不同的架构方式。服务端可以采用客户端/服务器、三层或者分布式架构等方式来进行设计,而web端则更多的采用众所周知的MVC架构模式(即Model、View、Controller),通过分离显示层与业务逻辑层进行开发。
10. http请求报文和响应报文的结构
用于HTTP协议交互的信息被称为HTTP报文。请求端(客户端)的HTTP报文叫做请求报文,响应端(服务器端)的叫做响应报文。HTTP报文本身是由多行数据构成的字符串文本。HTTP报文大致可分为报文首部和报文主体两块。两者由最初出现的空行来划分。通常,并不一定要有报文主体。
(1)请求报文
HTTP的请求报文由四部分组成(请求行+请求头部+空行+请求体):
①是请求方法,GET和POST是最常见的HTTP方法,除此以外还包括DELETE、HEAD、OPTIONS、PUT、TRACE。不过,当前的大多数浏览器只支持GET和POST,Spring 3.0提供了一个HiddenHttpMethodFilter,允许你通过“_method”的表单参数指定这些特殊的HTTP方法(实际上还是通过POST提交表单)。服务端配置了HiddenHttpMethodFilter后,Spring会根据_method参数指定的值模拟出相应的HTTP方法,这样,就可以使用这些HTTP方法对处理方法进行映射了。
②为请求对应的URL地址,它和报文头的Host属性组成完整的请求URL,
③是协议名称及版本号。
④是HTTP的报文头 ,报文头包含若干个属性,格式为“属性名:属性值”,服务端据此获取客户端的信息。
- Client-IP:提供了运行客户端的机器的IP地址
- From:提供了客户端用户的E-mail地址
- Host:给出了接收请求的服务器的主机名和端口号
- Referer:提供了包含当前请求URI的文档的URL
- UA-Color:提供了与客户端显示器的显示颜色有关的信息
- UA-CPU:给出了客户端CPU的类型或制造商
- UA-OS:给出了运行在客户端机器上的操作系统名称及版本
- User-Agent:将发起请求的应用程序名称告知服务器
- Accept:告诉服务器能够发送哪些媒体类型
- Accept-Charset:告诉服务器能够发送哪些字符集
- Accept-Encoding:告诉服务器能够发送哪些编码方式
- Accept-Language:告诉服务器能够发送哪些语言
- TE:告诉服务器可以使用那些扩展传输编码
- Expect:允许客户端列出某请求所要求的服务器行为
- Range:如果服务器支持范围请求,就请求资源的指定范围
- Cookie:客户端用它向服务器传送数据
- Cookie2:用来说明请求端支持的cookie版本
⑤是报文体,它将一个页面表单中的组件值通过param1=value1¶m2=value2的键值对形式编码成一个格式化串,它承载多个请求参数的数据。不但报文体可以传递请求参数,请求URL也可以通过类似于“/chapter15/user.html? param1=value1¶m2=value2”的方式传递请求参数。
(2)响应报文
HTTP的响应报文也由四部分组成( 响应行+响应头+空行+响应体):
①报文协议及版本;
②状态码及状态描述;
状态码详解mp.weixin.qq.com/s/xxxS5qG24…
③响应报文头,也是由多个属性组成;
- Age:(从最初创建开始)响应持续时间
- Public:服务器为其资源支持的请求方法列表
- Retry-After:如果资源不可用的话,在此日期或时间重试
- Server:服务器应用程序软件的名称和版本
- Title:对HTML文档来说,就是HTML文档的源端给出的标题
- Warning:比原因短语更详细一些的警告报文
- Accept-Ranges:对此资源来说,服务器可接受的范围类型
- Vary:服务器会根据这些首部的内容挑选出最适合的资源版本发送给客户端
- Proxy-Authenticate:来自代理的对客户端的质询列表
- Set-Cookie:在客户端设置数据,以便服务器对客户端进行标识
- Set-Cookie2:与Set-Cookie类似
- WWW-Authenticate:来自服务器的对客户端的质询列表
二、各种测试
1. 白盒测试
测试软件内部的结构和逻辑,检查程序的内部逻辑是否按照预期执行,并覆盖代码的不同路径(检查代码覆盖率,准出,手动跳过)。
只要针对技术文档+产品文档去设计测试用例,在功能方面的代码其实是都可以覆盖到的,正确和错误场景。涉及到比如说sso鉴权可以写个接口用例(有权限和无权限的token+断言接口的状态返回码)、抛出异常(是否正确地抛出了ArithmeticException异常,并且断言异常的消息是否正确)等。
语句覆盖(Statement Coverage):确保每一行代码都被执行至少一次(代码覆盖率)。
判定覆盖(Decision Coverage):确保每个条件语句的真值和假值都被测试到。
路径覆盖(Path Coverage):测试代码中的所有可能路径,包括循环和条件分支。
分支覆盖(Branch Coverage):确保每个分支都被至少执行一次。
条件覆盖(Condition Coverage):测试每个条件的真和假的情况。
2. 黑盒测试
面向用户需求:测试用例是根据用户需求和功能规范来设计的,目的是验证软件是否满足用户的期望。
强调功能覆盖:黑盒测试注重覆盖不同的功能路径和输入组合,以确保软件的各项功能都得到验证。
灰盒测试
是介于白盒测试与黑盒测试之间的一种测试,灰盒测试多用于集成测试阶段,不仅关注输出、输入的正确性,同时也关注程序内部的情况。灰盒测试不像白盒那样详细、完整,但又比黑盒测试更关注程序的内部逻辑
3. 降级测试
资源压力测试:模拟系统资源不足的情况,例如内存不足、CPU负载过高、网络带宽受限等,观察系统在这些条件下的表现和响应时间。
故障模拟:模拟系统中出现故障或异常的情况,例如数据库故障、网络断开、服务宕机等,检查系统是否能够适当地降级处理,以及在故障恢复后是否能够正确恢复正常功能。
降级处理测试:测试系统在面对资源压力或故障时是否能够稳定地降级处理,例如关闭部分功能、限制用户操作、提供缓存数据等,以确保系统依然可用并保持相对稳定。
性能监控:在降级测试过程中,监控系统的性能指标,包括响应时间、吞吐量、错误率等,以评估系统在降级状态下的表现。
4. 异常测试
(1)范畴
- 业务异常:主要从业务操作或业务流程方面考虑,一般会涵盖功能测试中的逆向测试
- 外部异常:外部调用的服务比如DB、缓存、MQ、其他接口等出现异常
- 网络异常:网络抖动、弱网
- 系统异常:系统健壮性问题,内存、磁盘、CPU的负载均衡
(2)测试方法
5. 接口测试
(1)概念:测试系统之间的接口,系统内部各个子模块的交互,数据交换、传递和控制管理过程,验证接口实现的正确性、稳定性和异常场景的容错能力。
(2)工具:Postman、SoapUI、RestAssured
(3)测试流程:
(4)测试要点:
- 参数校验
-
- 参数数量
-
-
- 增加参数:不影响
- 减少必填参数:明确提示
- 减少非必填参数:默认填充或忽略
-
-
- 参数类型
-
-
- 整型:输入字符串、浮点数、溢出
- 布尔型:true、false、字符串
- 字符串:空、null、开头结尾包含空格或制表符、中间包含空格、特殊字符
- 浮点型:格式不正确、科学计数法
- 枚举类型:正常、非法
-
-
- 参数名称
-
-
- 正确
- 错误
- 大小写
- 顺序变更
-
-
- 参数的长度或范围
-
-
- 无要求:浏览器与服务器对参数长度的限制、存储层字段长度
- 有要求:提醒、按照预定的规则截取或使用默认值
-
-
- 参数边界:超出范围
- 参数异常:数组空、null、undefined
- 参数转换:反序列化问题
- 安全性
-
- 敏感信息加密传输
- 鉴权:有接口权限-正常,无权限-无法访问,验签-修改验签内容查看是否可以正常访问
- 性能
-
- 接口性能并发
-
-
- 响应时间、吞吐率、并发量、资源使用情况
-
-
- 接口超时
-
-
- 下游依赖接口返回异常信息
- 下游接口超时
-
-
- 接口幂等:多次调用方法或接口不会改变业务状态,重复调用和单次调用结果一致,尝试多次请求查看返回结果是否一致
6. http接口测试
RPC接口是用于实现分布式系统之间的通信,它通常使用IDL定义接口,并通过编译器生成通信代码。
HTTP接口是一种使用HTTP协议的通信接口,常用于互联网应用中,基于RESTful架构风格。
Thrift接口是一个高效的跨语言远程调用框架,使用Thrift IDL来定义接口,并支持多种传输协议和序列化格式。
7. thrift接口测试
Thrift:
协议: Thrift使用自己的二进制协议,它是一种高效的序列化协议,适用于各种语言。
通信方式: Thrift支持多种传输层协议,如TCP、Unix domain sockets等,可以在不同机器、不同语言间通信。
代码生成: Thrift通过IDL(接口定义语言)来定义数据结构和接口,然后根据IDL生成不同语言的客户端和服务器端代码。
性能: 由于使用二进制协议和高度优化的序列化,Thrift通常比HTTP更快,适合高性能和低延迟的场景。
数据类型: Thrift支持丰富的数据类型,包括基本数据类型、自定义结构、集合等。
应用场景: Thrift适用于构建高性能、跨语言的通信系统,特别是在大规模分布式系统中使用,如Apache Cassandra、Apache HBase等。
HTTP接口:
协议: HTTP是一种基于文本的协议,通常使用JSON或XML等数据格式进行序列化。
通信方式: HTTP通常使用TCP作为传输协议,适用于客户端和服务器之间的通信。
代码生成: HTTP接口可以通过常用的Web框架(如Spring Boot、Express等)来实现,不需要特殊的代码生成步骤。
性能: 由于文本序列化和HTTP协议的开销,HTTP接口的性能通常比Thrift稍低,但对于一般应用来说足够。
数据类型: HTTP接口通常使用基本数据类型、JSON对象和数组等。
应用场景: HTTP接口适用于构建通用的Web服务,提供易于使用和理解的API,适合跨平台的应用,如移动应用、前端应用等。
总之,Thrift适用于需要高性能、跨语言、底层通信的场景,而HTTP接口更适合构建通用的Web服务,提供简单、易用的API。选择哪种方式取决于你的应用需求、性能要求以及跨平台支持等因素。
8. 单元测试
(1)概念
- 冒烟用例:对电路板接电,不坏,不冒烟==功能正常
- 单元测试:一块电路板有很多组件,先测试每个要用到的电子元器件。代码级测试,具有隔离性质,最小可测试单元通常是指函数或者类,一般以自动化的方式执行,底层模块或者核心模块
- 框架:JUnit(Java)、PyTest(Python)、NUnit(.NET)、Mocha(JavaScript)
(2)角度
- 开发:如果要实现正确的功能逻辑,会有哪几种正常的输入;是否有需要特殊处理的多种边界输入;各种潜在非法输入的可能性以及如何处理
- 测试:在明确了代码需要实现的逻辑功能的基础上,什么输入,应该产生什么输出
(3)测试流程
- 选择测试框架:Java常用的单元测试框架是Junit和TestNG,C/C++最常用的单元测试框架是CppTest和Parasoft C/C++test
- 对桩代码框架和Mock代码框架选型:主要依据是开发所采用的具体技术栈
引入计算代码覆盖率的工具:Java的JaCoCo,JavaScript的Istanbul - 单元测试执行、代码覆盖率统计和持续集成流水线: 每次代码递交,都会自动触发单元测试,并在单元测试执行过程中自动统计代码覆盖率
- 验收:以“单元测试通过率”和“代码覆盖率”为标准来决定本次代码递交是否能够被接受
(4)测试问题
- 紧密耦合的代码难以隔离
- 隔离后编译运行困难
- 代码本身可测试性较差,规模越大->可测试性越差
- 无法通过桩代码直接模拟系统底层函数的调用
- 后期代码覆盖率难提升
概念解释
驱动代码driver:调用被测函数的代码,驱动模块通常包含数据准备、调用被测函数和验证结果三个步骤,结构由单测框架决定
桩代码stub:用来代替真实代码的临时代码,A调用B,B还未实现,设计一个B'作为桩代码,起到了隔离和补齐的作用,使被测代码能够独立编译、链接,并运行
mock代码:Mock代码和桩代码的本质区别是测试期待结果的验证
| Mock code | Stub code |
|---|---|
| Mock方法有没有被调用以什么样的参数被调用 | 利用Stub来控制被测函数的执行路径 |
| 被调用的次数多个Mock函数的先后调用顺序 | 不会去关注Stub是否被调用以及怎么样被调用 |
| assert in mock | assert in driver |
9. 性能测试
10. 压力测试
(1)概念:评估系统在负载增加的情况下的性能表现和稳定性,找出系统的瓶颈和性能问题,模拟大量用户同时访问网站或者多个用户同时使用某个应用程序。
(2)工具:JMeter、LoadRunner、Gatling
(3)流程
- 先搭建一套与正式环境功能相同的测试环境,并且导入或者生成一批测试数据
- 在另一台服务器,启动多个线程并发地调用需要压测的接口(接口的参数一般也会设置成相同的,比如,想要压测获取商品信息的接口,那么压测时会使用同一个商品ID)
- 最后,通过统计访问日志或者查看测试环境的监控系统,来记录最终压测QPS是多少
(4)问题
- 最好使用线上的环境与数据,使用流量拷贝的方法
- 获取商品信息的时候,线上的流量会获取不同商品的数据,这些商品的数据有的命中了缓存,有的没有命中缓存。如果使用同一个商品ID来做压力测试,那么只有第一次请求没有命中缓存,而在请求之后会将数据库中的数据回种到缓存,后续的请求就一定会命中缓存了,这种压力测试的数据就不具备参考性了
- 不要从一台服务器发起流量,这样很容易达到这台服务器性能瓶颈,从而导致压力测试的QPS上不去,最终影响压力测试的结果。而且,为了尽量真实地模拟用户请求,我们倾向于把流量产生的机器放在离用户更近的位置,比如放在CDN节点上。如果没有这个条件,那么可以放在不同的机房中,这样可以尽量保证压力测试结果的真实性。
命中缓存(cache hit)
$ 是指在进行数据读取操作时,数据已经被缓存在本地缓存中,无需再从远程服务器或存储设备中获取数据,从而避免了网络传输的延迟和数据处理的开销,读取速度得到提升。相反,未命中缓存(cache miss)则表示需要从远程服务器或存储设备中获取数据。
$ 计算机中的缓存:内存、磁盘,缓存的数据:文件、图片、网页等
$ 通过缓存机制可以提高系统的读取速度,降低系统负载。常见的缓存机制包括浏览器缓存、CDN缓存、服务器缓存等。
$ 当请求一个数据时,系统会先查询缓存中是否有相应的数据,如果有,则直接返回缓存中的数据,否则会向远程服务器发送请求。命中缓存可以提高系统的响应速度,减少带宽压力和服务器负载。
CDN(Content Delivery Network)
$ 是指内容分发网络,是一种通过多个位于不同地理位置的节点服务器来分发网络内容,提高用户访问性能的技术。
$ CDN由一组高速缓存服务器组成,服务器分布在全球各地,可以在距离用户较近的地方缓存网站的静态内容(如图片、视频、JavaScript、CSS等),用户请求这些内容时,将被重定向至离用户最近的CDN节点进行响应,从而加快用户访问速度,减少等待时间。
$ CDN还可以对源站进行负载均衡,缓解源站的压力,提高网站的稳定性和可靠性。
11. 全链路压测
(1)概念:将接入层、所有后端服务、数据库、缓存、消息队列、中间件以及依赖的第三方服务系统及其资源,都纳入压力测试的目标之中。针对整个调用链路执行的压力测试也称为“全链路压测”
(2)关键点
- 流量隔离:区分压力测试流量和正式流量,这样可以针对压力测试的流量做单独的处理
- 风险控制:避免压力测试对于正常访问用户的影响
(3)模块
- 流量构造
-
- 流量拷贝:在系统高峰期时,将这些入口流量拷贝一份,在经过一些流量清洗的工作之后(比如过滤一些无效的请求),将数据存储在像是HBase、MongoDB这些NoSQL存储组件或者亚马逊S3这些云存储服务中,称之为流量数据工厂
- 拷贝方法
-
-
- 直接拷贝负载均衡服务器的访问日志,数据就以文本的方式写入到流量数据工厂中
- 流量拷贝工具GoReplay,它可以劫持本机某一个端口的流量,将它们记录在文件中,传送到流量数据工厂
-
-
-
-
- 流量下发节点和服务部署节点不要在同一机房,对压测流量标记在HTTP的请求头中增加一个标记项,比如说叫做is stress test,在流量拷贝之后,批量在请求中增加这个标记项,再写入到数据流量工厂中
-
-
- 产生模块
- 压测数据隔离模块
-
- 针对读取数据的请求(一般称之为下行流量),我们会针对某些不能压测的服务或者组件,做Mock或者特殊的处理
-
-
- 业务开发会依据请求记录用户的行为,比如,用户请求了某个商品的页面。在压测的时候,肯定会增加这些行为数据,比如原本一天商品页面的浏览行为是一亿次,而压测之后变成了十亿次,这样就会对业务报表产生影响,影响后续的产品方向的决策。因此,我们对于这些压测产生的用户行为做特殊处理,不再记录到大数据日志中。
- 系统会依赖一些推荐服务,推荐一些你可能感兴趣的商品,但是这些数据的展示有一个特点就是展示过的商品就不再会被推荐出来。如果你的压测流量经过这些推荐服务,大量的商品就会被压测流量请求到,线上的用户就不会再看到这些商品了,也就会影响推荐的效果。
-
-
- 针对写入数据的请求(一般称之为上行流量),我们会把压测流量产生的数据写入到影子库,也就是和线上数据存储完全隔离的一份存储系统中。针对不同的存储类型,使用不同的影子库的搭建方式
-
-
- 如果数据存储在MySQL中,我们可以在同一个MySQL实例,不同的Schema中创建一套和线上相同的库表结构,并且把线上的数据也导入进来。
- 如果数据是放在Redis中,对压测流量产生的数据,增加一个统一的前缀,存储在同一份存储中。
- 还有一些数据会存储在Elasticsearch中,针对这部分数据,可以放在另外一个单独的索引表中。
-
- 系统健康度检查和压测流量干预模块
12. APP测试
13. WEB测试
三、自动化测试
1. QA分支合并流程
git工程拉取自己的分支,提交,合并到develop分支
master上最新的代码merge到dev,提pr,将dev分支合并到master
2. git常用命令
//创建分支
git checkout -b {new_branch}
//本地分支
git branch
//远端分支
git branch -r
//所有分支
git branch -a
//重命名分支
git branch -m {old_branch} {new_branch}
//删除本地分支(如果没有merge到master会报错)
git branch -d {branch}
//强制删除
git branch -D {branch}
//删除远端分支
git push origin :{branch}
//删除本地存在,但远端已经删除的分支
git remote prune origin
3. postman
(1)概念:REST API测试工具,网页调试与发送网页HTTP请求,并能运行测试用例的的Chrome插件
(2)功能
- 模拟各种HTTP requests
- collection包含多个request集合作为一个test case
- 设定变量与环境,编辑request,校验response的时候,总会需要重复输入某些字符,比如url,postman允许我们设定变量来保存这些值
(3)原理:模拟客户端向服务器发送请求报文
(4)测试工具比较
| 工具 | 接口类型 | 测试类型 | 脚本扩展能力 | 参数化 | 持续集成 |
|---|---|---|---|---|---|
| SoapUI | Soap、Rest | 功能、压力、安全 | Groovy脚本 | 可通过文件、数据库、Excel、Grid等加载 | maven+jenkins |
| Jmeter | Rest、Soap等 | 功能、压力 | Bean shell (java) | 可通过csv、txt等文件加载 | ant+jenkins |
| Postman | Rest | 功能 | JavaScript | 可通过CSV/JSON文件加载 | nodejs+newman+jenkins |
4. JUnit= Java+Unit Testing
(1)如果JUnit方法的返回类型为’string’, 会发生什么?
JUnit测试方法旨在返回” void”。因此执行将失败。
(2)如何测试”protected”方法?
在与目标类相同的包中声明测试类
(3)如何测试”private”方法?
没有直接方法可以测试私有方法。因此必须执行手动测试
5. TestNG
- 什么是TestNG?
TestNG(NG for Next Generation)是一个测试框架,可以与 selenium 或任何其他自动化工具集成,以提供多种功能,如断言、报告、并行测试执行等。
- TestNG 有哪些优点?
- TestNG 提供了不同的断言来帮助检查预期和实际结果
- 提供测试方法的并行执行
- 定义一种测试方法对其他测试方法的依赖
- 可以为 Selenium 中的测试方法指定优先级
- 允许将测试方法分组到测试组中
- 允许使用@DataProvider 注释进行数据驱动的测试,它具有对报告的固有支持
- 支持使用@Parameters 注释参数化测试用例
- TestNG 与 Selenium WebDriver 有何不同?
- Selenium 是一种自动化工具,我们可以使用它来自动化基于 Web 的应用程序
- 可以在我们的自动化套件中拥有不同的功能,例如不同类型的断言、报告、并行执行和参数化等
- Selenium有助于“自动化”,而 TestNG 有助于“测试”功能
- testng.xml文件有什么用?
用于配置整个测试套件。在 testng.xml 文件中,我们可以创建测试套件、创建测试组、标记并行执行的测试、添加侦听器以及将参数传递给测试脚本。我们还可以使用这个 testng.xml 文件从命令提示符/终端或 Jenkins 触发测试套件
- 有哪些常用的TestNG注解
@Test 注释将方法标记为测试方法
@BeforeSuite在此套件中的所有测试运行之前,带注释的方法只会运行一次
@AfterSuite在此套件中的所有测试都运行后,带注释的方法将只运行一次
@BeforeClass – 在当前类中的第一个测试方法被调用之前,带注释的方法只会运行一次。
@AfterClass – 在当前类中的所有测试方法都运行后,带注释的方法将只运行一次。
@BeforeTest – 带注释的方法将在任何属于 标签内的类的测试方法运行之前运行。
@AfterTest – 注释方法将在属于 标签内的类的所有测试方法运行后运行。
@ BeforeMethod -被注释的方法将通过@Test注释标记每个测试方法之前运行。
@ AfterMethod -被注释的方法将通过@Test注释标记每个测试方法之后运行。
@DataProvider – @DataProvider 注解用于将测试数据传递给测试方法。测试方法将根据通过数据提供者方法传递的数据行数运行。
- 基于不同注解的测试方法的执行顺序是什么?
Suite->Test->Class->Method 顺序结合 Before annotations->Test annotations->After annotations 顺序。所以,执行的顺序是
@BeforeSuite-----@BeforeTest-----@BeforeClass-----@BeforeMethod-----@Test-----@AfterMethod-----@AfterClass-----@AfterTest-----@AfterSuite
- TestNG 提供了哪些常见的断言?
assertEquals(String actual, String expected, String message) 该方法比较两个字符串,如果对比不匹配就打印出message信息
assertNotEquals(double data1, double data2, String message)
assertFalse(布尔条件,字符串消息)
assertTrue对布尔值求值,看是否为“真”,condition为”false”,而期望是“true”,这时候会打印出message
assertNotNull(Object 对象)失败(布尔条件,字符串消息)真(字符串消息)
- 我们如何使用 TestNG 是一种测试方法依赖于其他方法?
在TestNG的@Test注解中使用dependsOnMethods参数,我们可以让一个测试方法只有在依赖测试方法成功执行后才能运行。
@Test(dependsOnMethods = { "preTests" })
- 如何在循环中多次运行测试方法(不使用任何数据提供者)?
使用 invocationCount 参数并将其值设置为整数值,使测试方法在循环中运行 n 次。
@Test(invocationCount = 10)
- 什么是线程池大小?我们如何使用它?
所述 threadPoolSize属性指定的线程的数目被分配到的测试方法。这与invocationCount 属性结合使用 。线程数将除以 invocationCount 属性中指定的测试方法的迭代次数。
@Test(threadPoolSize = 5, invocationCount = 10)
- TestNG中的软断言和硬断言有什么区别?
软断言 (SoftAssert) 允许我们在一个测试方法中拥有多个断言,即使断言失败,测试方法仍会继续执行剩余的测试。最后可以使用 softAssert.assertAll() 方法整理所有断言的结果。即使第一个断言失败,测试仍将继续执行并在第二个断言下方打印消息。
在任何失败的情况下硬断言都会使测试执行停止,阻止执行测试方法中的任何进一步步骤。
问题 17。如果 testNG 测试未在指定时间内执行,如何使该测试失败?答。我们可以使用 @Test 注解的timeOut属性。分配给此 timeOut 属性的值将用作上限,如果测试未在此时间范围内执行,则它将因 timeOut 异常而失败。
@Test(timeOut = 1000)
- 我们如何使用 TestNG 将参数传递给测试脚本?
使用@Parameter 注释和testng.xml 中的“parameter”标签,我们可以将参数传递给测试脚本。
- 我们如何使用 TestNG 创建数据驱动的框架?
使用@DataProvider,我们可以创建一个数据驱动的框架,其中数据被传递到关联的测试方法,并针对从@DataProvider 方法传递的不同测试数据值进行多次迭代测试。使用@DataProvider 批注的方法返回对象的二维数组。
//Data provider returning 2D array of 3*2 matrix
- TestNG中@Listener注解有什么用?
TestNG 为我们提供了不同类型的侦听器,我们可以使用这些侦听器在事件被触发时执行一些操作。通常,testNG 侦听器用于配置报告和日志记录。testNG 中使用最广泛的侦听器之一是 ITestListener 接口。它有 onTestSuccess、onTestFailure、onTestSkipped 等方法。我们需要实现这个接口,创建一个我们自己的监听器类。在使用@Listener 注释之后, 我们可以使用指定对于特定测试类应该使用我们定制的侦听器类。
@Listeners(PackageName.CustomizedListenerClassName.class)
- TestNG中@Factory注解有什么用
@Factory 注释有助于测试用例的动态执行。使用@Factory 注释,我们可以在运行时将参数传递给整个测试类。传递的参数可以被该类的一个或多个测试方法使用。示例 - 有两个类 TestClass 和 TestFactory 类
- @Factory 和 @DataProvider 注解有什么区别?
@Factory 方法创建测试类的实例,并使用不同的数据集运行该类中的所有测试方法。而@DataProvider 绑定到单个测试方法并多次运行特定方法。
6. UI自动化测试中常见的UI元素定位方式
UI自动化测试是指通过脚本或工具自动模拟用户操作,对应用程序的用户界面进行测试。在UI自动化测试中,需要通过定位元素来与应用程序的UI进行交互。以下是一些常见的UI元素定位方式:
- ID定位:每个UI元素在代码中都有唯一的标识符(ID),可以通过ID来定位元素。这是一种稳定且推荐的定位方式,因为ID是唯一的。
- Name定位:有些UI元素会有名称属性(Name),可以通过名称来定位元素。
- XPath定位:XPath是一种用于在XML文档中定位元素的语言,可以通过XPath表达式来定位UI元素。XPath定位方式较为灵活,但也较为复杂,不推荐在稳定性要求高的场景中使用。
- CSS选择器定位:CSS选择器是一种用于选择HTML元素的方法,可以通过CSS选择器来定位UI元素。
- ClassName定位:每个UI元素通常都有一个唯一的类名,可以通过类名来定位元素。
- LinkText和PartialLinkText定位:适用于定位链接元素,LinkText是精确匹配链接文本,PartialLinkText是部分匹配链接文本。
- TagName定位:通过HTML标签名来定位元素,但由于标签名可能不唯一,一般不推荐使用。
- Accessibility ID定位:适用于移动端自动化测试,在iOS中称为Accessibility ID,在Android中称为Content Description。
7. 如何测试静态方法
(1)将private方法的访问符改为 default (因为default访问修饰符课在同一个包中访问)
(2)用反射机制 method.getDeclaredMethod()
四、其他问题
1. 印象比较深刻的bug
历史遗留问题,有的时候提出来,开发那边会觉得,这是已有逻辑,之前就这样。
印象中有两个比较深刻,其中一个是和输入法有关,苹果手机有自带输入法,进行输入的时候是拼音会以字母的形式出现在输入框内,选择联想出来的汉字之后,输入框内才会出现汉字,包括PC端无论是windows还是mac都是类似的,但是安卓端不一样,安卓端的输入法一般是第三方,比如百度输入法等等,它的拼音打字的拼音会出现在输入键盘的界面内,选择汉字后才会填充输入框。
这种输入框限制
C端因为我觉得做本地生活这种产品,不管是toB还是toC,使用体验都非常重要,尤其是输入框字符这种,这是最基础的功能点,一定要重视。
第二个就是测外卖直播,外卖直播的商品管理是通过另一个直播软件及进行设置,并与商家端和用户端的商品关联,商家端的
数据清洗,如何做三表一致,脏数据的产生
2. 如何理解自动化测试
(1)提高效率
相较于手工测试,自动化测试能够快速地执行大量的测试用例,节省了测试人员的时间和精力。特别是在频繁的回归测试场景下,自动化测试可以迅速验证软件功能是否受到影响
(2)保证质量
自动化测试可以提高测试的准确性和一致性。自动化测试用例是基于事先定义好的测试用例编写的,因此在测试过程中不会因为人为的误操作或遗漏而引入错误。同时,自动化测试能够多次重复执行相同的测试用例,确保每次测试的结果一致,人们都不愿意重复的做同一件事,那么交给程序去做是最好了。
(3)难以构造的数据,可以mock
3. 测试用例评审的流程是什么
(1)测试用例是否按照公司定义的模板进行编写的;
(2)测试用例的本身的描述是否清晰,是否存在二义性;
(3)测试用例内容是否正确,是否与需求目标相一致;
(4)测试用例的期望结果是否确定、唯一的;
(5)操作步骤应与描述是否相一致;
(6)测试用例是否覆盖了所有的需求;
(7)测试设计是否存在冗余性;
(8)测试用例是否具有可执行性;
(9)是否从用户层面来设计用户使用场景和业务流程的测试用例;
(10)场景测试用例是否覆盖最负载的业务流程;
(11)用例设计是否包含了正面、反面的用例;
(12)对于由系统自动生成的输出项是否注明了生成规则;
(13)用例应包含对中间和后台数据的检查;
(14)测试用例应有正确的名称和编号;
(15)测试用例应标注有执行的优先级;
(16)测试用例包含相关的配置信息:测试环境、数据、前置测试用例、用户授权等;
(17)自动化测试脚本必须带有注释(注释应包括:目的、输入、期望结果等);
4. bug不能复现怎么办
环境问题:考虑是否是环境或者账号问题,特殊账号或者某个特殊环境下
复现:按照原有操作步骤进行复现,步骤不能出错
代码层面:与开发人员配合,让开发人员对相应的代码检查,看是否通过代码层面检查出问题
保留日志:保留发生bug时的log,附加到提交的Bug中,希望可以通过log中找到一些蛛丝马迹。
多次测试:进行多次测试 更换设备进行测试
5. web和app测试的区别
(1)系统架构方面:
- web项目,是b/s架构,基于浏览器的,web测试只要更新了服务器端,客户端就会同步会更新
- App项目,是c/s架构,必须要有客户端,用户需要安装客户端,App项目则需要客户端和服务器都更新
(2)性能方面:
- web页面主要会关注响应时间
- app则还需要关心流量、电量、CPU、GPU、Memory这些
- 它们服务端的性能没区别,都是一台服务器。
(3)兼容方面:
- web是基于浏览器的,所以更倾向于浏览器和电脑硬件,电脑系统的方向的兼容
- app测试则要看分辨率,屏幕尺寸,还要看设备系统
(4)安装卸载方面:
- web测试是基于浏览器的所以不必考虑安装卸载
- app是客户端的,则必须测试安装、更新、卸载。除了常规的安装、更新、卸载还要考虑到异常场景。包括安装时的中断、弱网、安装后删除安装文件此外APP还有一些专项测试:如网络、适配性
(5)自动化测试
- Web大多用的selenium webdriver
- app是appium
6. 如果一个问题认为是bug 但开发说不是 你怎么处理
(1)首先进行bug重现,在开发的前面重新操作一遍给他看,确定大家看到的都是同一个现象,有可能因为操作账号或者设备不同有差异
(2)校队需求 看是否是同一版本的需求 如果不是同个版本 那就确定哪一方需求是最新的
(3)如果需求一致 双方意见还达不到一致 那就找产品经理确认
(4)开会讨论决定 找相关人员决定最终的决定
7. 上线之后出现bug怎么解决
评估bug的影响范围,检查bug是否业务核心环节的功能问题,检查bug是否涉及到信息泄露等
如果是优化类型的缺陷,可以等其他任务上线时一并修改,并记录为优化
影响小的bug,根据场景+业务操作去复现,开发结合日志(系统日志、数据库日志、操作日志、debug日志),定位原因,修改完成后进行回归测试,保证被修复,然后发布到线上
影响大的bug,可以通过回滚版本的方式,或者将功能降级或关闭
8. 为什么要进行抓包
A.有些时候公司没有标准的接口文档,测试人员只能抓包来获取接口测试。
B.抓包可以迅速找到请求,通过抓包可以查看整个请求的过程,以及响应时间,还可以分辨前台与后台Bug.
C.通过抓包,可以查看是否有敏感信息,如(用户密码,个人账户信息等数据)
D.可以通过抓包进行测试,拦截请求,修改请求数据,查看对应的响应结果,抓包本身就是接口的一部分
9. 接口测试需要登录
主要内容包括方案
I、打开全局Cookie按钮:第一步:请求登陆接口、第二步:访问其他接口,则都处于了登陆状态
II、利用环境变量,先请求登陆接口,再请求后续接口、1、请求登陆接口,将响应COOKIE赋值给变量:、2、调用变量,手动给header添加Cookie参数
1、请求登陆接口,将响应COOKIE赋值给变量:
为了处于登陆态,需要先请求登陆接口,此举目的是为了模拟用户的登陆行为,获取需要的登陆参数(这里是Cookie)。
将登陆接口返回的PHPSESSID(这个是SessionID,PHPSESSID是针对PHP作为后端接口的SessionID变量名,其他语言的变量名可能不同)设为环境变量。
apt.variables.set("login_var", response.cookies["PHPSESSID"]);
2、调用变量,手动给header添加Cookie参数
接着返回收藏接口,进到header选项,参数值选择cookie,参数值输入: PHPSESSID={{login_var}}。
此举是为了利用登陆接口返回的Cookie伪造请求的PHPSESSID。或者也可以定义个全局header,这样就不用每个接口都设置一遍了
10. 对于加密接口,签名接口如何进行测试?
加密接口:在调用接口的时候,首先要弄清楚接口的加密方式什么什么?
如∶
① 对称式的加密方式(私钥加密)∶不常用的有DESAES,常用是Base64加密方式。
② 非对称的加密方式(双钥加密): RSA加密方式。
③ 只加密不解密(MD5加密)
④ 自定义加密规则。混合加密方式。
了解加密规则(签名规则)之后,在请求接口之前先要对参数做对应的加密(签合)之后在发送请求。单一加密方式,postman和Jmeter有些是支持的,postman使用javascript脚本实现,Jmeter使用beansheI中的java代码实现。
11. 接口测试中上下游接口有数据依赖如何处理?
假如一个事务需要顺序调用2个接口:A和B接口, B依赖A接口的响应数据,这时候在执行B接口之前必须完成A接口,并通过某些手段获得A接口的特定数据给B接口使用。
上下游接口的数据依赖无非就是准备测试数据,数据一般有三种方式获得:
独立统一的测试数据库, A、B需要的数据都可以从库里拿到
假如B依赖A创造的数据,那么每次执行B之前必须执行A去做数据创建
通过正则表达式动态获得A的返回数据,并保存到变量中,通过参数化的方式传递给B接口
12. 接口测试的基本步骤?
1)获取请求报文数据
通过fiddler工具或者API接口文档获得请求报文参数,其中就包括请求方式(get、post、put等)、URL地址、请求的query string parameter以及请求的body数据。
2)借助工具模拟请求报文并发送
把第一步中获得的参数,整理到jmeter、postman、soapui等接口参数工具中,模拟接口请求并发送该请求。
3)获得响应结果
使用接口测试工具发送请求后,会返回响应报文,分析响应报文中的数据是否是符合要求的。
4)断言:判断实际结果是否与预期相同
在工具中也可以添加预设的断言,在运行接口测试后,会自动返回接口是否实现正确。我们可以使用响应报文的响应状态码、响应的headers头部或者响应的正文数据(html、json格式等)进行断言。
13. 一个接口用例中有多个API接口,前后两个 API 之间如何进行参数传递的?
也就是上下游接口的依赖,A接口的响应结果a,是B接口的请求入参。
一种方法是:动态获取a的值。
另一种方法:比如在接口测试工具Postman、Jmeter中设置参数变量。也就是说A接口运行完毕后,将结果提取出来放在全局变量中。这样一来,其余接口就可以获取到这个值了。如果这个变量不想放在全局中共享,也可以只提供给当前测试套件使用。
14. 你在实施接口自动化测试的过程中,如果某些接口第一次调用长时间没有返回,如何保证流程顺利进行又可以记录错误信息?
如果一个接口长时间没有返回,会影响整体测试的执行时间以及执行结果。
所以我们要为每个接口设置一个超时时间,比如3秒。一个接口超过3秒还没有返回,就可以定位为异常。
当然也不是一个接口一次调用超时了,就一定是异常了,要设置失败重试(一般为3次),如果执行了3次还是超时,就可以认为是一个异常。在Python中很多单元测试框架都可以添加用例失败重跑机质。另外也可以使用while循环实现用例的重复执行。
当一个接口用例,最终重试了三次依然失败或超时,我们就需要将该问题记录到系统日志中并最终显示在测试报告中。但是该用例执行完毕后,还要保证剩下的用例继续执行。如果在不使用单元测试框架的情况下,我们就需要捕获接口调用超时或错误的异常,以保证测试任务不会中断。
总结一下,要保证每个接口用例执行不会时间过长,不会单次失败就误报,又能成功记录错误信息,保证测试任务不中断。我们需要做到三点:设置超时、添加失败重跑机质、记录错误日志,有必要时要捕获异常对象。
在自动化实施过程中,除了要保证正常流程之外,还要对异常场景做合理的处置。
15. 接口测试如何设计测试用例?
接口测试一般考虑入参形式的变化和接口的业务逻辑,一般设计接口测试用例采用等价类、边界值、场景法居多。
接口测试设计测试用例的思路如下:
1.正常用例,验证接口逻辑是否正确。根据业务逻辑、输入参数、输出值的描述,对正常输入情况下所得的输出值
2.异常用例,为了保证数据的安全及程序在异常情况下的逻辑的正确性而进行的测试。
模块接口测试的主要包括以下几个方面:
1)鉴权码token异常(鉴权码为空<没有鉴权码>,错误的鉴权码,过期的鉴权码)。
2)请求参数正常/异常。
3)返回结果校验,数据库比对
16. 平常做接口测试的过程中发现过哪些bug?
可以发现很多在页面上操作发现不了的bug。可以修改请求参数,突破前端页面输入限制。
举例说明:
1、比如一个订单支付时,我们页面上是无法改变订单金额的,但我们可以通过抓包工具捕获订单支付请求,然后修改订单金额后提交,然后出现了一个原价100元的订单我们用1分钱完成了支付。
2、比如一个转账的页面,前端做了限制导致我们无法在转账金额的输入框输入负数,但我们可以通过抓包工具修改,然后出现了一个转账金额为负数的bug。
17. 怎么理解RPC接口,有什么作用?
RPC 的全称为:Remote Procedure Call Protocol即远程过程调用协议。RPC通过网络从远程的服务器上请求服务无需了解底层技术协议 。RPC采用的是客户端/服务端模式,RPC的作用是开发方便、直接,安全性高,特别是在一些大型项目中,内部的子系统及接口比较多的情况下,采用网络分布式的多个APP开发更加容易 。
下图为RPC的工作流程: