本文目录导读:

我来介绍几种常见的代码覆盖率统计脚本编写方法,根据不同语言和工具进行分类:
Python 覆盖率统计
使用 pytest-cov
#!/bin/bash
# coverage_python.sh
# 安装依赖
pip install pytest pytest-cov coverage
# 运行测试并生成覆盖率报告
pytest --cov=./src \
--cov-report=term-missing \
--cov-report=html:coverage_html \
--cov-report=xml:coverage.xml \
tests/
更完整的 Python 脚本
#!/usr/bin/env python3
# coverage_stats.py
import subprocess
import sys
import os
def run_coverage():
"""运行覆盖率统计"""
# 配置参数
source_dir = 'src' # 源代码目录
test_dir = 'tests' # 测试目录
output_dir = 'coverage_reports'
# 创建输出目录
os.makedirs(output_dir, exist_ok=True)
# 运行覆盖率检查
commands = [
f'coverage run --source={source_dir} -m pytest {test_dir}',
f'coverage report -m',
f'coverage html -d {output_dir}/html',
f'coverage xml -o {output_dir}/coverage.xml'
]
for cmd in commands:
print(f"执行: {cmd}")
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
if result.returncode != 0:
print(f"错误: {result.stderr}")
sys.exit(1)
print(result.stdout)
# 解析覆盖率数据
print(f"\n覆盖率报告已生成到: {output_dir}/html/")
if __name__ == '__main__':
run_coverage()
JavaScript/TypeScript 覆盖率
使用 Istanbul/nyc
// package.json 配置
{
"scripts": {
"coverage": "nyc --reporter=html --reporter=text --reporter=lcov npm test",
"coverage:check": "nyc --check-coverage --lines=80 --functions=80 --branches=80 npm test"
}
}
Shell 脚本版本
#!/bin/bash
# coverage_js.sh
# 配置
COVERAGE_THRESHOLD=80
PROJECT_DIR=$(pwd)
echo "=== JavaScript 覆盖率统计 ==="
# 安装依赖
npm install --save-dev nyc mocha
# 运行测试并生成覆盖率
npx nyc \
--reporter=html \
--reporter=text \
--reporter=lcov \
--report-dir=./coverage \
npm test
# 检查覆盖率是否达标
if [ $? -eq 0 ]; then
echo "覆盖率报告生成成功"
# 解析覆盖率数据
COVERAGE=$(npx nyc report --reporter=text-summary | grep Lines | awk '{print $3}' | sed 's/%//')
echo "当前行覆盖率: ${COVERAGE}%"
if (( $(echo "$COVERAGE < $COVERAGE_THRESHOLD" | bc -l) )); then
echo "警告: 覆盖率低于 ${COVERAGE_THRESHOLD}%"
exit 1
fi
else
echo "覆盖率测试失败"
exit 1
fi
Java 覆盖率统计
使用 JaCoCo
<!-- pom.xml 配置 -->
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.11</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>check</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule>
<element>BUNDLE</element>
<limits>
<limit>
<counter>LINE</counter>
<value>COVEREDRATIO</value>
<minimum>0.80</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
Shell 脚本版本
#!/bin/bash
# coverage_java.sh
# 配置
MIN_COVERAGE=80
JACOCO_VERSION=0.8.11
echo "=== Java 覆盖率统计 ==="
# 检查工具
command -v mvn >/dev/null 2>&1 || { echo "需要 Maven"; exit 1; }
# 运行测试并生成覆盖率
mvn clean test jacoco:report
# 检查覆盖率
if [ -f "target/site/jacoco/jacoco.csv" ]; then
# 解析 CSV 文件获取覆盖率
LINE_COVERAGE=$(awk -F',' 'NR>1 {sum+=$8; count++} END {printf "%.2f", sum/count}' target/site/jacoco/jacoco.csv)
echo "代码行覆盖率: ${LINE_COVERAGE}%"
if (( $(echo "$LINE_COVERAGE < $MIN_COVERAGE" | bc -l) )); then
echo "覆盖率低于 ${MIN_COVERAGE}%"
exit 1
fi
fi
通用覆盖率统计脚本
#!/usr/bin/env python3
# universal_coverage.py
import os
import sys
import json
import subprocess
from pathlib import Path
class CoverageCollector:
"""通用的覆盖率收集器"""
def __init__(self, config_file='.coveragerc'):
self.config = self._load_config(config_file)
self.results = {}
def _load_config(self, config_file):
"""加载配置文件"""
default_config = {
'python': {
'enabled': True,
'source': 'src',
'test_dir': 'tests',
'threshold': 80
},
'javascript': {
'enabled': True,
'test_dir': 'test',
'threshold': 80
},
'java': {
'enabled': True,
'threshold': 80
}
}
if os.path.exists(config_file):
with open(config_file, 'r') as f:
return json.load(f)
return default_config
def collect_python_coverage(self):
"""收集 Python 覆盖率"""
print("\n=== Python 覆盖率 ===")
try:
cmd = [
'coverage', 'run',
f'--source={self.config["python"]["source"]}',
'-m', 'pytest', self.config['python']['test_dir']
]
subprocess.run(cmd, check=True)
result = subprocess.run(
['coverage', 'report', '--format=json'],
capture_output=True, text=True
)
if result.returncode == 0:
data = json.loads(result.stdout)
return {
'lines': data.get('totals', {}).get('percent_covered', 0),
'branches': data.get('totals', {}).get('percent_covered_branches', 0)
}
except Exception as e:
print(f"Python 覆盖率失败: {e}")
return None
def collect_js_coverage(self):
"""收集 JavaScript 覆盖率"""
print("\n=== JavaScript 覆盖率 ===")
try:
subprocess.run(
['npx', 'nyc', '--reporter=json', 'npm', 'test'],
check=True
)
if os.path.exists('.nyc_output/coverage.json'):
with open('.nyc_output/coverage.json', 'r') as f:
data = json.load(f)
total_lines = total_covered = 0
for file_data in data.values():
for line, count in file_data.get('s', {}).items():
total_lines += 1
if count > 0:
total_covered += 1
return {
'lines': (total_covered / total_lines * 100) if total_lines > 0 else 0
}
except Exception as e:
print(f"JavaScript 覆盖率失败: {e}")
return None
def generate_report(self):
"""生成覆盖率报告"""
report = {
'timestamp': None,
'project': os.getcwd(),
'results': {}
}
from datetime import datetime
report['timestamp'] = datetime.now().isoformat()
# 收集各语言覆盖率
if self.config.get('python', {}).get('enabled', False):
report['results']['python'] = self.collect_python_coverage()
if self.config.get('javascript', {}).get('enabled', False):
report['results']['javascript'] = self.collect_js_coverage()
# 保存报告
report_file = 'coverage_report.json'
with open(report_file, 'w') as f:
json.dump(report, f, indent=2)
print(f"\n报告已保存到: {report_file}")
# 检查覆盖率阈值
self._check_thresholds(report)
return report
def _check_thresholds(self, report):
"""检查覆盖率是否达标"""
all_passed = True
for lang, data in report['results'].items():
if data:
threshold = self.config.get(lang, {}).get('threshold', 80)
coverage = data.get('lines', 0)
if coverage < threshold:
print(f"⚠ {lang}: {coverage:.1f}% (低于 {threshold}%)")
all_passed = False
else:
print(f"✓ {lang}: {coverage:.1f}%")
if not all_passed:
print("\n❌ 部分语言未达到覆盖率要求")
sys.exit(1)
else:
print("\n✅ 所有语言覆盖率达标")
if __name__ == '__main__':
collector = CoverageCollector()
collector.generate_report()
配置示例 (.coveragerc)
{
"python": {
"enabled": true,
"source": "src",
"test_dir": "tests",
"threshold": 85,
"exclude": ["tests/*", "migrations/*", "setup.py"]
},
"javascript": {
"enabled": true,
"test_dir": "test",
"threshold": 80,
"exclude": ["node_modules/*", "dist/*"]
},
"java": {
"enabled": true,
"threshold": 85,
"exclude": ["test/*", "generated/*"]
}
}
CI/CD 集成脚本
# .github/workflows/coverage.yml
name: Code Coverage
on: [push, pull_request]
jobs:
coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install dependencies
run: |
pip install pytest pytest-cov coverage
npm install
- name: Run coverage
run: python coverage_universal.py
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v2
with:
files: ./coverage.xml,./coverage/lcov.info
flags: unittests
name: codecov-umbrella
这些脚本可以根据具体项目需求进行调整和组合使用,选择哪种方案主要取决于:
- 项目使用的编程语言
- 现有的测试框架
- CI/CD 集成需求
- 是否需要多语言支持
建议从简单的单语言脚本开始,根据需要逐步扩展。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播