SpringBoot接入JaCoCo实践教程

本书作者:测试开发刚哥,文章版权归个人所有,未经授权请勿转载。 静态接入和动态接入 SpingBoot可以通过2种方式接入JaCoCo:Maven和Agent。Maven方式是静态接入,在编译时计算代码覆盖率。Agent方式是动态接入,服务启起来以后,能实时根据代码命中情况计算代码覆盖率。 教程代码已上传开源项目:https://github.com/dongfanger/mini Maven pom.xml添加依赖: <dependency> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <version>0.8.7</version> </dependency> 添加配置: <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${project.parent.version}</version> </plugin> <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <version>0.8.7</version> <executions> <execution> <id>default-prepare-agent</id> <goals> <goal>prepare-agent</goal> </goals> </execution> <execution> <id>default-report</id> <goals> <goal>report</goal> </goals> </execution> </executions> </plugin> </plugins> </build> 点击maven的install: target/site/jacoco目录下就生成了覆盖率报告: Agent 下载jacoco文件后解压,提取2个文件: 使用命令启动SpringBoot,启动参数添加-javaagent: java -javaagent:jacoco/jacocoagent.jar -jar target/mini-0.0.1-SNAPSHOT.jar 此时会生成1个jacoco.exec文件,这个文件就是覆盖率数据文件,采用以下命令根据数据文件生成HTML报告: java -jar jacoco/jacococli.jar report jacoco.exec --classfiles ./target/classes/ --sourcefiles ./src/main/java/ --html ./report 接下来就来验证动态特性。把report目录和jacoco.exec都删了,因为jacoco每次部署只能分析一次。把服务停掉后,重新启动。这一次不直接分析,而是先用postman调一下接口: 然后再分析一把: ...

teprunner测试平台用例前置模块开发

本书作者:测试开发刚哥,文章版权归个人所有,未经授权请勿转载。 本文开发内容 现在正式进入测试相关功能开发。teprunner测试平台底层是pytest,中间层是tep,还没了解的朋友可以先看看tep的文章,整个平台的设计思路和后面用例的执行都会基于这个工具。tep的测试用例是放在.py文件里面的,全局变量或者说环境变量是引用的env_vars,公共函数和复用接口是引用的fixtures,在做成平台后,需要把这两个部分独立为两个功能模块。多个项目的接口自动化数据需要隔离开来,要有个项目管理功能。本文将开发四个用例前置模块: 后台管理–项目管理 接口自动化–语法说明 接口自动化–环境变量 接口自动化–fixtures 语法说明给出了环境变量、fixtures、用例示例(单个接口、多个接口–增删改查)、请求方法(get、post、put、delete)的使用方法。 编写后端代码 先创建名为teprunner的app: django-admin startapp teprunner 在settings的INSTALLED_APPS中添加配置让app生效: 并在urls.py添加路由: 编辑user/fixtures/user.json,添加一个接口自动化的菜单: 截图只截了管理员,测试和开发角色,也需要添加上。access均为true,这三个角色都可以访问。添加后把数据同步到数据库: python manage.py loaddata user 编辑teprunner/models.py,新增模型: 包括了项目、环境变量和fixture三张表。Project.env_config用于给项目配置多个环境。不同项目不同环境的环境变量不一样,在EnvVar中添加了project_id和env_name,并按(“project_id”, “env_name”, “name”)作为唯一键,不允许重复。不同项目的fixtures不同,不关心环境,在Fixture中只添加了project_id。 Fixture.code用于存放代码,字段类型为models.TextField,容纳更多字符。 models编写好后,迁移到数据库: python manage.py makemigrations python manage.py migrate 新建teprunner/serializers.py文件,新增序列化器: 数据库字段的命名是用的下划线,接口返回前端和前端传参是用的驼峰,所以这里通过source这种方式给env_config、project_id、env_name、creator_nickname进行了序列化器的重命名。为了前端更方便处理,使用serializers.CharField把int转化为了str,由于请求时id非必须,增加参数required=False。 teprunner会有很多视图,写在一个文件里面有点臃肿,这里创建views文件夹,新增views/project.py项目视图: Django REST framework的ModelViewSet视图类能节省很多代码,只需要三行就把项目增删改查接口做了。project_env是函数视图,请求方法为GET,它的作用是返回项目环境列表,当前项目和当前环境,默认为第一个项目和第一个环境。 前端需要切换不同项目和不同环境,下拉框数据来源于这个接口。 新建views/envvar.py新增环境变量视图: 环境变量跟项目和环境是强关联的,需要根据项目环境进行过滤,所以重写了list方法,从前端请求拿到curProjectId和curEnvName,通过EnvVar.objects.filter进行过滤。from django.db.models import Q支持多种过滤条件,这在后面的代码中还能看到,比如模糊匹配。 新建views/fixture.py新增fixture视图: fixture跟项目是强关联的,需要根据项目进行过滤,所以重写了list方法,从前端请求拿到curProjectId,通过Fixture.objects.filter进行过滤。Fixture有个creatorNickname字段,新增fixture时使用的是当前登录用户的昵称,修改fixture时需要用已保存的创建者,重写update方法来实现这个处理。 最后,新建teprunner/urls.py文件,把视图添加到路由中: 编写前端代码 编辑package.json,添加依赖: fixtures是代码形式的,这是测试平台第一次使用代码编辑组件。添加依赖后记得执行npm install进行安装。 编辑router/index.js: 添加接口自动化的路由,并把home重定向改为语法说明路由。children表示子路由。path是路由地址。meta.title用于显示菜单名。 编辑views/console/index.vue: 添加项目管理菜单。新建ProjectManagement.vue和AddProject.vue,添加项目管理增删改查代码,跟用户管理类似,不再另加赘述。值得注意的是环境配置placeholder="请输入环境英文名(多个环境英文逗号分隔)",因为tep.env_vars.mapping会用到环境名作为key,所以只能用英文名! 编辑components/WrapComponent.vue,添加一个插槽: ...

把RPC包进事务的暗坑

本书作者:测试开发刚哥,文章版权归个人所有,未经授权请勿转载。 # 方式:把判断放进 SQL,一条语句的原子性 rows = db.execute(""" UPDATE pay_record SET status = 'PAID' WHERE order_no = ? AND status = 'INIT' """, order_no) if rows == 0: return "已处理" # 别人改过了,我不是第一个 grant_coupon(order_no) # 只有改成功的那个才发券 return "success" grant_coupon失败会发生什么? 券永久丢失,该发没发,资损。 第一次请求: UPDATE status: INIT → PAID ✅ 已提交,改不回去了 grant_coupon(order_no) ❌ 抛异常 / 超时 / 下游挂了 第二次请求: rows = db.execute("UPDATE ... WHERE status = 'INIT'") # status已是PAID # rows == 0 return "已处理" # ← 被自己的幂等逻辑拦住,不会执行grant_coupon 包进一个事务能解决吗 把update和grant_coupon这两个操作,包进一个事务里,要么同时执行,要么同时回滚,是不是就解决了? ...

工作以后,换种方式学习

工作碎片化时间,理解,思考,总结,能够加速成长。

如何用tep完成增删改查接口自动化

tep的设计理念是让人人都可以用Python写自动化,本文就来介绍如何用tep完成增删改查接口自动化。

2026-01-04 · 2 分钟 · 385 字 · 测试开发刚哥 · 原创项目 · #Tep

80道高频算法题Python版

80道高频算法题来源于牛客网,这些答案都经过了我验证,可以复制粘贴后提交通过:

Django官方为什么没有标准项目结构

Django官方并没有提供标准的项目结构,于是网上众说纷纭,百花齐放,一千个读者有一千个哈姆雷特。那我们该怎么设计项目结构呢?在回答这个问题之前,先了解一下Django原生的目录和文件都是干嘛的。

Dockerfile文件万字全面解析

Dockerfile是一个文本文件,包含一些Docker指令。执行docker build,Docker就会执行Dockerfile里面的指令,来自动创建镜像。

2026-01-03 · 14 分钟 · 2820 字 · 测试开发刚哥 · Java生态 · #Golang

Flask官方推荐项目结构竟然是这样

Flask有个特点:千人千面。它没有硬性规定,你必须采用哪种项目结构来组织代码,这就导致每个人都按照自己的习惯和喜好来写,写出来的项目结构往往是千差万别。在Flask2.0的官方文档中,有一节内容介绍了Flask的项目结构,我们可以窥探一番。

2026-01-03 · 1 分钟 · 119 字 · 测试开发刚哥 · Python生态 · #Flask

Git比较分支差异的3个命令

查看本地分支