测试左移:代码分析平台 SonarQube 实战
代码分析介绍
代码分析所关注的质量指标:
- 代码坏味道
- 代码规范
- 技术债评估
- bug 和漏洞
- 代码重复度
- 单测与集成
- 测试用例数量
- 覆盖率
常见代码分析工具:
- 综合性的代码分析平台
SonarQube
:支持自定义代码分析规则
- IDE 辅助功能
- Xcode、Android Studio
- 阿里巴巴 Java 开发手册:IDE 插件支持
- 独立的静态分析工具
- FindBugs、AndroidLint、ScanBuild
- 阿里巴巴 Java 开发手册:PMD 插件
SonarQube 使用流程:
SonarQube 平台搭建
临时部署
# 自带小型内存级db
docker run -d \
--name sonarqube_dev \
-p 9000:9000 -p 9092:9092 \
sonarqube
访问主机 IP:9000
:
正式部署
# 设置变量
db_instance=postgres_prod # postgres 实例名称
sonarqube_instance=sonarqube_prod # sonar 实例名称
data_dir=/root/sonarqube # 数据挂载主目录
mkdir -p $data_dir
# 创建网络
docker network create sonarqube
# 启动 pg 数据库
docker run -d \
--name $db_instance \
--network sonarqube \
-p 5432:5432 \
-e POSTGRES_USER=sonarqube \
-e POSTGRES_PASSWORD=sonarqube \
-e PGDATA=/var/lib/postgresql/data/pgdata \
-v $data_dir/postgresql:/var/lib/postgresql/data \
postgres
# 创建数据目录
mkdir $data_dir/sonarqube_data # 数据目录
mkdir $data_dir/sonarqube_extensions # 扩展目录
mkdir $data_dir/sonarqube_logs # 日志目录
# 启动 soarqube 时所需的配置
sysctl -w vm.max_map_count=524288
sysctl -w fs.file-max=131072
ulimit -n 131072
ulimit -u 8192
# 启动 soarqube 部署
docker run -d \
--name $sonarqube_instance \
--network sonarqube \
-p 9000:9000 -p 9092:9092 \
-e SONARQUBE_JDBC_USERNAME=sonarqube \
-e SONARQUBE_JDBC_PASSWORD=sonarqube \
-e SONARQUBE_JDBC_URL="jdbc:postgresql://$db_instance/sonarqube" \
-v $data_dir/sonarqube_data:/opt/sonarqube/data \
-v $data_dir/sonarqube_extensions:/opt/sonarqube/extensions \
-v $data_dir/sonarqube_logs:/opt/sonarqube/logs \
sonarqube
# 启动过程较慢,可以从日志查看启动进度
docker logs -f sonarqube
代码分析实战
Sonar 创建项目
Sonar 平台默认登录账号:admin/admin
填写任意字符后生成 Token(注意保存):
SONARQUBE_TOKEN=e74425b959d9b4666195d7278fafee8fac5d6a72
以 Maven 为例:
mvn clean verify sonar:sonar \ # sonar:sonar 需要先在本地maven中安装插件
-Dsonar.projectKey=demo \
-Dsonar.host.url=http://192.168.3.222:9000 \
-Dsonar.login=e74425b959d9b4666195d7278fafee8fac5d6a72
开源项目演练
使用以下开源平台进行代码分析演练:
git clone https://github.com/linlinjava/litemall.git
cd litemall
# 打包项目
mvn clean package
SONARQUBE_TOKEN=e74425b959d9b4666195d7278fafee8fac5d6a72
# 使用 java 11
# 使用 sonar 对该项目代码进行分析,并上传结果到 sonar 平台中
mvn sonar:sonar \
-Dsonar.host.url=http://192.168.3.222:9000 \
-Dsonar.login=$SONARQUBE_TOKEN
-Dsonar.projectKey=demo
在 sonar 平台上查看代码构建的分析概况:
- bug:36 个
- 漏洞:1 个
- 安全漏洞:35 个
- 技术债: 66 天
- 代码不规范问题:22000 + 个
- 没有进行单元测试
- 有重复代码
代码构建-分析明细:
空指针分析:
单元测试-代码覆盖率实战
非侵入式的生成 jacoco 代码覆盖率数据:
# 查找生成的 jacoco 覆盖率数据文件路径
find $PWD -name "jacoco.*"
mvn clean \
org.jacoco:jacoco-maven-plugin:0.8.6:prepare-agent \
test \
org.jacoco:jacoco-maven-plugin:0.8.6:report \
sonar:sonar \
-Dsonar.host.url=http://192.168.3.222:9000 \
-Dsonar.login=$SONARQUBE_TOKEN \
-Dsonar.projectKey=demo \
-Dsonar.coverage.jacoco.xmlReportPaths="$PWD/**/**/**/**/jacoco.xml" \
-Dmaven.test.failure.ignore=true \
-Dmaven.test.skip=false
- 以上命令表示:先进行编译单测生成覆盖率数据,再将覆盖率数据上传到 sonar 上。
- 使用通配符匹配所有 jacoco 报告,则 sonar 还会统计每次新增代码的覆盖率及其趋势图。
- 关键数据:
- 覆盖率报告:**/jacoco
- 覆盖率原始 dump 数据:**/jacoco.exec
另一种做法:侵入式的生成 jacoco 代码覆盖率数据
- 在 pom 中增加 jacoco 插件
- mvn clean test jacoco:report
集成测试-代码覆盖率实战
做法:
- 使用 jacoco 的 tcp 模式。
- 生成覆盖率数据:
- 精准测试做法:在每次集成测试的用例之后(teardown)获取覆盖率数据并重置覆盖率数据。
- 传统覆盖率做法:在所有集成测试的用例之后(teardown_session)中获取覆盖率数据。
- 覆盖率数据合并(merge)。
- 将覆盖率数据 report 生成 xml 文件。
- 上传 Java 相关(单测)测试数据到 sonar,可使用 sonar.junit.reportPaths、sonar.coverage.jacoco.xmlReportPaths 参数。
- 上传集成测试执行数据与覆盖率数据到 sonar,则可使用 sonar.testExecutionReportPaths、sonar.coverageReportPaths 参数。
示例:在进行集成测试(生成覆盖率数据)后,再利用 scanner 上传覆盖率数据到 sonar 上
# 查找 jacoco 覆盖率数据文件所在路径
find $PWD -name "jacoco.*"
# 上传覆盖率数据到 sonar
mvn \
sonar:sonar \
-Dsonar.host.url=http://192.168.3.222:9000 \
-Dsonar.login=$SONARQUBE_TOKEN \
-Dsonar.projectKey=demo \
-Dsonar.coverage.jacoco.xmlReportPaths="$PWD/**/**/**/**/jacoco.xml" \
-Dmaven.test.failure.ignore=true \
-Dmaven.test.skip=false