代码覆盖率从0到100的入门实践
JaCoCo全称是Java Code Coverage,Java代码覆盖率,广泛运用于各种测试平台对Java代码的全量覆盖率和增量覆盖率进行统计,分析代码行差异,度量单元测试效果。Jacoco也是精准测试的技术实现手段之一。
JaCoCo全称是Java Code Coverage,Java代码覆盖率,广泛运用于各种测试平台对Java代码的全量覆盖率和增量覆盖率进行统计,分析代码行差异,度量单元测试效果。Jacoco也是精准测试的技术实现手段之一。
本书作者:测试开发刚哥,文章版权归个人所有,未经授权请勿转载。 什么是HAR包? HAR(HTTP Archive format),是一种JSON格式的存档格式文件,通用扩展名为 .har。 HAR包是JSON格式的,打开后,重点关注entries里面的request和response,包含了请求和响应信息。 流量录制 怎么获取HAR包呢?可以网上搜索方法,浏览器F12、抓包工具(Charles、Proxyman等)都可以将HTTP请求导出为HAR包。 生产级别的流量录制很复杂,想要了解的话可以参考阿里开源项目:https://github.com/alibaba/jvm-sandbox-repeater 回放对比 本文重点介绍在导出HAR包后,怎么通过Python来实现回放对比。 使用介绍 一、将HAR包转换为pytest用例 har_file为har包路径,profile配置开启回放,调用Har.har2case()方法将HAR包转换为pytest用例。 转换后会生成: demo_test.py 与HAR同名的pytest用例文件 demo-replay-diff 对比结果目录,暂时为空 sqlite.db 存储HAR包响应数据,标记为expect 二、执行pytest用例 from tep.libraries.Diff import Diff from tep.libraries.Sqlite import Sqlite def test(HTTPRequestKeyword, BodyKeyword): var = {'caseId': '023f387db398504889e0afb8dd1bc99d', 'requestOrder': 1, 'diffDir': '/Users/wanggang424/Desktop/PycharmProjects/tep/tests/demo/case/har/demo-replay-diff'} url = "https://postman-echo.com/get?foo1=HDnY8&foo2=34.5" headers = {'Host': 'postman-echo.com', 'User-Agent': 'HttpRunnerPlus', 'Accept-Encoding': 'gzip'} ro = HTTPRequestKeyword("get", url=url, headers=headers) # user_defined_var = ro.response.jsonpath("$.jsonpath") assert ro.response.status_code < 400 Sqlite.record_actual((ro.response.text, var["caseId"], var["requestOrder"], "GET", "https://postman-echo.com/get?foo1=HDnY8&foo2=34.5"), var) url = "https://postman-echo.com/post" headers = {'Host': 'postman-echo.com', 'User-Agent': 'Go-http-client/1.1', 'Content-Length': '28', 'Content-Type': 'application/json; charset=UTF-8', 'Cookie': 'sails.sid=s%3Az_LpglkKxTvJ_eHVUH6V67drKp0AGWW-.PidabaXOnatLRP47hVyqqepl6BdrpEQzRlJQXtbIiwk', 'Accept-Encoding': 'gzip', 'sails.sid': 's%3Az_LpglkKxTvJ_eHVUH6V67drKp0AGWW-.PidabaXOnatLRP47hVyqqepl6BdrpEQzRlJQXtbIiwk'} body = r"""{"foo1":"HDnY8","foo2":12.3}""" ro = BodyKeyword(body) # ro = BodyKeyword(body, {"$.jsonpath": "value"}) body = ro.data ro = HTTPRequestKeyword("post", url=url, headers=headers, json=body) # user_defined_var = ro.response.jsonpath("$.jsonpath") assert ro.response.status_code < 400 Sqlite.record_actual((ro.response.text, var["caseId"], var["requestOrder"], "POST", "https://postman-echo.com/post"), var) url = "https://postman-echo.com/post" headers = {'Host': 'postman-echo.com', 'User-Agent': 'Go-http-client/1.1', 'Content-Length': '20', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'Cookie': 'sails.sid=s%3AS5e7w0zQ0xAsCwh9L8T6R7QLYCO7_gtD.r8%2B2w9IWqEIfuVkrZjnxzm2xADIk34zKAWXRPapr%2FAw', 'Accept-Encoding': 'gzip', 'sails.sid': 's%3AS5e7w0zQ0xAsCwh9L8T6R7QLYCO7_gtD.r8%2B2w9IWqEIfuVkrZjnxzm2xADIk34zKAWXRPapr%2FAw'} ro = HTTPRequestKeyword("post", url=url, headers=headers, data=body) # user_defined_var = ro.response.jsonpath("$.jsonpath") assert ro.response.status_code < 400 Sqlite.record_actual((ro.response.text, var["caseId"], var["requestOrder"], "POST", "https://postman-echo.com/post"), var) Diff.make(var["caseId"], var["diffDir"]) 执行时会记录实际请求响应,存入sqlite数据库,标记为actual。 ...
连续调用两次,第一次提交成功,第二次会被驳回——串行重复,系统是防住了的。
在对安卓进行测试时,我们需要把 apk 传到安卓机上,对请求抓包,同时监控应用日志。本文就来讲讲具体操作。
本书作者:测试开发刚哥,文章版权归个人所有,未经授权请勿转载。 运行文件 JMeter下载地址为: https://jmeter.apache.org/download_jmeter.cgi 最新版本为5.4.1,依赖于Java8+,下载后无需安装,解压即用。解压后的目录和文件如下: bin 二进制文件目录,包括配置文件、启动文件、启动jar包、示例脚本。比如Windows和Linux系统的两个启动脚本: docs API离线帮助文档。 extras 辅助功能,可用于Ant、Jenkins集成。 lib lib根目录下存放JMeter基础jar包,lib/ext目录下存放第三方或自定义扩展jar包。 licenses 证书文本文件。 printable_docs 离线帮助文档。 LICENSE 证书说明。 NOTICE 版权声明。 README 简介。 测试计划 JMeter以图形界面方式启动后,首先映入眼帘的是左侧的TestPlan,测试计划: JMeter的UI界面只能同时编辑一个测试计划,如果想再编辑另外一个测试计划,必须再打开一个JMeter界面。这是因为测试计划对应的是.jmx文件!不同的.jmx文件只能在不同的界面中编辑。 JMeter界面是通过组件拖拽的方式来编写脚本的,脚本的根目录是测试计划。根节点只能有一个,作为根节点,测试计划很适合来做全局配置,比如在User Defined Variables处添加键值对格式的全局变量。 测试计划是默认节点,JMeter还有另外一个不可缺少的次节点:Thread Group,线程组。 多线程 性能测试工具的目的是用少量电脑产生成百上千个并发请求。多进程和多线程正好能用来实现这个需求,书上有句关于进程和线程的至理名言:“进程是操作系统分配资源的最小单位,线程是程序执行的最小单位”。该如何理解呢?前一句的意思是说,每个应用程序都有对应的进程,按照进程来分配资源,可以使得资源利用最大化,避免浪费。后一句的理解得从一个故事讲起,很久以前,进程拿着资源找CPU执行。CPU一看进程太大,说我处理不了。进程只能拆成多个线程给CPU,不但能执行了,还能在线程之间灵活切换。 多进程和多线程都可以用来模拟并发请求。JMeter是用Java语言写的程序,运行在JVM虚拟机之上,进程的开销比线程大很多,JVM为了保证足够性能,控制了进程的数量。如果用多线程,单台电脑能提供了负载有限,那么就只能用多线程。JMeter只支持多线程! 另外一个性能测试工具LoadRunner支持多进程和多线程。 用户即线程 JMeter除了Thread Group,其他地方都是用的另外一个词:User。实际上它们是一个意思,用户就是线程。JMeter的运行原理就是用多个线程来模拟多个用户!以下是简单示例: 从图中可以看出,有两个线程组,Thread Group 1和Thread Group 2,它们分别定义了自己组内的用户要做的事情。不同线程组做的事情是不一样的,但是同一线程组内部做的事情是一模一样的。我们在写JMeter脚本的时候,实际上是在定义每个用户要做哪些事。当运行脚本的时候,JMeter会启动多个线程,都来执行这个脚本,按照我们写的进行执行。 由于每个线程启动时间不一样,线程执行时资源环境也有区别,导致线程的执行进度并不完全一致,比如一些线程已经登录完了,另一些线程可能才刚开始登录。后面的文章会给出一些解决办法。 远程运行 一台机器提供了线程数量有限,如果想要施压更大的并发,那么就需要多台机器。JMeter天然支持多台机器并发: 控制机和负载机本质上没有区别,同一台机器既可以做控制机,也可以做负载机,取决于你的负载设计。控制机的作用是管理多台远程负载机,控制远程负载机脚本运行,收集远程负载机测试结果。负载机是实际产生并发的机器,它们向被测应用系统发起负载。 运行逻辑如下: 远程负载机启动Agent客户端,等待控制机连接。 控制机连接上远程负载机。 控制机发送指令到远程负载机启动线程。 远程负载机运行脚本,回传结果数据。 控制机收集结果并显示。 操作步骤如下: 远程负载机启动jmeter-server.bat。 在控制机bin\JMeter.properties文件中,修改remote_hosts,添加远程负载机的ip和port,多个远程负载机ip 用逗号分隔,如remote_hosts=192.168.0.1:1664,192.168.0.2:1664。1664是默认RMI端口号(Remote Method Invocation,远程方法调用)。 在控制机菜单栏Run执行Remote命令: 如果远程负载机需要参数或jar包,可以手动先把环境准备好,也可以使用自动化工具在脚本运行前从控制机发送到远程负载机。 小结 本文先从JMeter运行文件讲起,启动后默认有测试计划,建线程组,线程即用户,用多线程来模拟多用户,这就是JMeter运行起来施压的原理。为了解决单台机器负载能力有限的问题,JMeter还提供了远程运行方式,既可以在局域网用多台机器来控制,也可以部署到云服务器上,进行云压测。
注解(Annotations)是JUnit的标志性技术,本文就来对它的20个注解,以及元注解和组合注解进行学习。
大家好,我是刚哥。
本书作者:测试开发刚哥,文章版权归个人所有,未经授权请勿转载。 一、引言 黑盒测试犹如案发现场,只能根据表象推断事件经过。 代码评审即深入调查,挖掘蛛丝马迹的线索,揭示背后的真相。 “They think I am hiding in the shadows, but I am the shadows.” 二、黑盒测试与白盒测试的区别 黑盒测试存在一些局限性: 可能无法发现与系统实现相关的问题 可能无法覆盖所有的测试场景 测试效率较低,比如准备物料、模拟场景 强依赖需求文档,如果文档不全,测试会漏 对于测试人员来说,可以在代码评审阶段,通过白盒测试改进测试的质量和效率。 三、代码评审的定义和意义 代码评审,Code Review(CR),是一种通过检查代码来提高代码质量的过程。 对于测试人员来说,参与代码评审,可以尽量提前发现问题,减少修复代价,提高效能。 四、代码评审的形式 多人讨论 组织会议,研发牵头讲解代码,架构和测试参与,讨论交流。这是最普遍的一种形式。 Code Diff 查看Code Diff,可以借助Gitlab或IDEA,比较分支差异或版本差异。 对比时机: 提测前和测试中,自行走查代码 发现缺陷,定位代码原因 修复缺陷后,评估影响范围 上线前,是否夹带代码 精准测试 评估测试用例的代码覆盖率,查漏补缺,Jacoco的on-the-fly模式支持动态收集代码覆盖率数据。 五、代码评审的方法 面向业务,面向业务,面向业务。重要的事情说三遍。 刚开始做代码评审,很容易把注意力集中在找代码规范问题上面,比如命名不规范、注释不清楚、代码实现冗长等。这些问题不是测试人员关注的重点,需要由研发团队或代码扫描工具来解决。 在做Code Diff时,也没必要把每个文件、每行代码的意思搞懂,比如研发对代码结构做了调整,在diff时要梳理清楚的话,ROI会非常低,因为既消耗时间,又发现不了问题。 那该怎么做代码评审呢? 关注业务: 跟需求文档比较,哪些需求是遗漏的,哪些代码是补充的,哪些代码是夹带的 关注核心业务代码逻辑,使用条件覆盖、路径覆盖等方法设计测试用例 优化测试用例,针对代码实现考虑异常、边界、幂等、并发等场景 代码评审要求测试人员具备代码能力,理解编程语言,掌握软件设计,熟悉代码结构和架构,多与开发同学交流,共同优化代码质量。 六、代码评审的实际案例 1、空指针异常 import org.mybatis.spring.SqlSessionTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class UserService { private final SqlSessionTemplate sqlSessionTemplate; @Autowired public UserService(SqlSessionTemplate sqlSessionTemplate) { this.sqlSessionTemplate = sqlSessionTemplate; } public void getUserById(String userId) { User user = sqlSessionTemplate.selectOne("com.example.mapper.UserMapper.getUserById", userId); System.out.println(user.getName()); // 可能导致空指针异常 } } 如果取到的 user 对象为空,就会导致空指针异常。 ...
错误码不分层的接口,你只能靠 msg 断言,改个文案用例就跑失败。返回快照的字段返回了实时,数据就无法核对上。
本书作者:测试开发刚哥,文章版权归个人所有,未经授权请勿转载。 如何评价接口自动化项目 我理想中的接口自动化项目,是有一套脚本,能够100%覆盖核心业务场景,能够回归线上频繁出现的问题,能够支持手工无法验证的场景,能够抛出偶现问题,能够包含容易遗漏的边界场景、异常场景,每天都能定时运行,出具报告,给予反馈。 用实际的指标量化下: 功能测试自动化率 = 自动化测试用例数/总测试用例数 自动化发现bug占比 = 自动化发现的bug/总bug数 自动化发现bug有效性 = 自动化发现的有效bug/自动化提交的bug总数 自动化执行成功率 = 自动化执行成功的次数/自动化执行总次数 周活跃自动化用例占比 = (∑每周执行过的自动化测试用例)/(∑周维度自动化测试用例) 应用维度自动化代码覆盖率 = 自动化用例覆盖代码行数/应用维度代码总行数 现状是什么(Situation) 我负责的业务是发票中台,数据流简化后如下图所示: 发票中台对调用方提供RPC服务,底层有读写MySQL、同步ES、消息队列、异步任务等服务,上游是用户和订单,需要账号、增票资质、订单等物料;下游是财务,推送申请单给财务开具发票等。 发票的接口自动化在多年前是写了的,用Java+TestNG+RPC本地化了一套框架来实现,因为人员离职和业务变更,这套自动化到我手上的时候,已经不能用了,本地化的接口自动化项目也无法做数据度量,只有接口测试平台写的自动化用例才会被统计到。 任务是什么(Task) 我给自己定的绩效是在Q2完成95条自动化用例,按照一个标准化的自动化项目来实现发票的接口自动化,结合测试环境、测试物料、流水线、精准分析,打造一个个人的稳定的沉淀物,无论是晋升还是求职,都能拿来讲点故事。 行动是什么(Action) 编写自动化用例的方式 1、最理想的方式,是能够录制线上流量直接转换为自动化用例,修修改改即可。虽然我们有流量录制回放平台,但是它跟接口自动化平台并没有打通,很可惜不能采取这种方式。 2、参考线上流量日志,抓取接口、入参,人工转化为自动化用例。 3、参考接口的代码设计,比如controller/provider/sdk都定义了应用接口,能知道哪些覆盖到了,哪些还需要补充。 4、根据入参模板自行构造参数。参数个数太多的话造起来很麻烦。 我主要采用第2种和第3种方式结合来编写自动化用例。 典型自动化用例 前置步骤:初始化数据,将订单发票类型更新为3。 预设变量:提供参数化数据。 执行步骤:调用修改订单发票类型接口,将发票类型3改为2,入参引用预设变量。 财务接口:依赖测试物料无法满足,通过Mock来返回模板数据,让接口继续往下走。 基础断言:接口响应状态码200。 业务断言:调用订单列表查询接口,用JSONPath提取响应中的发票类型,断言已经改成了2。 场景用例 数据准备:通过物料工具造订单数据,写入MySQL数据库中。 更新MySQL数据:更新订单的部分字段数据,触发binlake,将数据同步至ES,因为提交开票申请是读取的ES数据;从预设变量获取orderId。 提交开票申请:从ES读取订单数据,提交开票申请;从预设变量获取orderId和userId。 查询申请单号:根据订单号查询申请单号;从预设变量获取orderId和userId。用JSONPath提取申请单号,存入动态变量中。 推送财务:把申请单号推送给财务;从动态变量获取applyId。 覆盖更多代码 ①看代码: 在Java工程里面的Controller/Provider找到所有接口,分析可以用来做自动化的接口,设计自动化用例进行覆盖。 ②代码覆盖率: 借助于jacoco,在执行自动化用例后,把代码覆盖率跑出来,分析没覆盖的代码,补充更多正常/异常/边界的自动化用例。也就是精准测试。 自动化巡检 每天早上8点,定时任务执行用例集;发送邮件,抄送测试组、开发组、领导,让测试、开发和领导都知道自动化建设情况;如果出现问题,一定要在当天解决,并邮件回复问题原因;确保当天的自动化用例结果都是正确的;第二天接着继续巡检。 流水线 在持续集成中,引入自动化用例环节,把自动化用例跑通作为提测卡点,不通过可以驳回。 产出是什么(Result) 定性来看: 结合测试环境、测试物料、自动化、流水线、精准测试,完成了一个能对环境和业务进行稳定性巡检,能对研发提测进行质量门禁,能对应用进行代码覆盖率分析的接口自动化项目。 定量来看: 功能测试自动化率 = 自动化测试用例数/总测试用例数 95/100=95% 自动化发现bug占比 = 自动化发现的bug/总bug数 2/53=3.7% 自动化发现bug有效性 = 自动化发现的有效bug/自动化提交的bug总数 2/2=100% 自动化执行成功率 = 自动化执行成功的次数/自动化执行总次数 5396/5621=96% 周活跃自动化用例占比 = (∑每周执行过的自动化测试用例)/(∑周维度自动化测试用例) 77% 应用维度自动化代码覆盖率 = 自动化用例覆盖代码行数/应用维度代码总行数 39% 这个Q主要完成了核心流程和重要接口的自动化用例,还需要持续补充场景用例和异常/边界的自动化用例。 ...