多语言变异测试质量门禁 CLI 工具
Project description
mutation-gate
多语言变异测试质量门禁 CLI 工具。支持 Python(mutmut)、Java(pitest)、JavaScript/TypeScript(Stryker)三种后端,输出 PASS/FAIL 裁定和存活变异体列表,可直接嵌入 CI 流水线。
安装
pip install mutation-gate
开发环境:
git clone <repo>
pip install -e '.[dev]'
外部依赖(按语言选装):
| 语言 | 工具 | 安装 |
|---|---|---|
| Python | mutmut | pip install mutmut |
| Java | Maven + JDK | apt install maven openjdk-21-jdk |
| JS/TS | Node.js + npm | nodejs.org,项目内 npm install @stryker-mutator/core @stryker-mutator/jest-runner |
快速上手
Python — mutmut
# 执行变异测试,通过阈值 80%
mutation-gate run --paths src/calc.py --threshold 80
# 查询上次结果(不重新执行)
mutation-gate check --paths src/calc.py --threshold 80
Java — pitest
项目需包含 pitest-maven 插件(见 pom.xml 示例)。
mutation-gate run \
--paths src/main/java/com/example/Calculator.java \
--threshold 75
# 多个文件
mutation-gate run \
--paths src/main/java/com/example/Calculator.java \
--paths src/main/java/com/example/StringUtils.java \
--threshold 75
JavaScript / TypeScript — Stryker
项目根目录需有 stryker.config.json。
# JS(自动检测后端)
mutation-gate run --paths src/calc.js --threshold 70
# TypeScript
mutation-gate run --paths src/stack.ts --threshold 70
# 强制指定后端
mutation-gate run --paths src/app.js --tool stryker --threshold 70
命令参考
run — 执行变异测试
mutation-gate run [选项]
必选:
-p, --paths TEXT 源文件路径(可多次指定)
常用选项:
--threshold FLOAT 通过阈值,默认 80.0%
--tool TEXT 强制后端:mutmut / pitest / stryker
--json 以 JSON 格式输出(供 CI 解析)
--clean 执行前先清除旧缓存
--show-survivors INT 展示 survivor 数量(0=全部,-1=不展示)
--coverage TEXT coverage.json 路径(开启覆盖率联合门禁)
示例输出:
## Mutation Gate: PASS
| 指标 | 值 |
|----------|-------------|
| Score | 81.8% |
| Threshold| 70.0% |
| Killed | 18 |
| Survived | 4 |
| Total | 22 |
| Scope | Calculator.java |
### Survivors
- `Calculator.java:33` [ConditionalsBoundaryMutator] changed conditional boundary
check — 查询缓存结果(不重新执行)
mutation-gate check --paths src/calc.py --threshold 80
mutation-gate check --paths src/calc.py --threshold 80 --json
缓存位置:.mutmut-cache(mutmut)、target/pit-reports/mutations.xml(pitest)、reports/mutation/mutation.json(Stryker)。
status — 查询运行状态
mutation-gate status # 文本格式
mutation-gate status --json # JSON 格式
clean — 清除缓存
mutation-gate clean # 自动检测后端
mutation-gate clean --tool pitest
覆盖率联合门禁
先用 pytest-cov 生成覆盖率报告,再传给 run 或 check:
pytest --cov=src --cov-report=json:coverage.json
mutation-gate run \
--paths src/calc.py \
--threshold 80 \
--coverage coverage.json
输出额外显示行覆盖率和分支覆盖率,任一未达标则裁定 FAIL。
REPL 交互模式
无子命令启动进入交互式 shell,支持 Tab 补全和历史记录:
mutation-gate
╔══════════════════════════════╗
║ mutation-gate v0.1.0 ║
║ 输入 help 查看可用命令 ║
╚══════════════════════════════╝
> run --paths src/calc.py
> check --paths src/calc.py --json
> quit
退出码
| 退出码 | 含义 |
|---|---|
0 |
PASS — 变异分数达标 |
1 |
FAIL — 变异分数低于阈值 |
2 |
ERROR — 工具未安装 / 缓存不存在 / 参数错误 |
CI 集成
完整 workflow 文件位于 .github/workflows/:
| 文件 | 触发条件 | 内容 |
|---|---|---|
ci.yml |
push / PR → master | Python 3.10/3.11/3.12 矩阵测试 + mutation-gate 自检 |
publish.yml |
push tag v* |
build → twine check → 发布至 PyPI(OIDC 免密) |
在 job 中嵌入 mutation-gate 步骤:
- name: Install
run: pip install -e '.[dev]'
- name: Mutation Gate
run: |
mutation-gate run \
--paths src/calc.py \
--threshold 80 \
--json
--json 输出结构:
{
"verdict": "FAIL",
"score": 57.14,
"threshold": 80.0,
"killed": 4,
"survived": 3,
"total": 7,
"scope_files": ["src/calc.py"],
"survivors": [
{"file": "src/calc.py", "line": 13, "mutator": "mutmut",
"description": "--- src/calc.py\n+++ ..."}
]
}
打包与发布
依赖
pip install build twine
构建
python -m build
在 dist/ 下生成两个文件:
dist/
mutation_gate-0.1.0-py3-none-any.whl # 二进制分发包(推荐安装)
mutation_gate-0.1.0.tar.gz # 源码包
Wheel 仅含 src/mutation_gate/ 运行时代码,不包含测试和文档。
验证
# 检查包元数据是否符合 PyPI 规范
twine check dist/*
# 在隔离环境中测试安装
python -m venv /tmp/test-env
/tmp/test-env/bin/pip install dist/mutation_gate-0.1.0-py3-none-any.whl
/tmp/test-env/bin/mutation-gate --help
发布到 PyPI
自动发布(推荐):推送版本 tag 即触发 .github/workflows/publish.yml,
通过 OIDC Trusted Publishing 免密上传,无需在 Secrets 中存储 API Token。
# 升版本 → 提交 → 打 tag → 推送
vim pyproject.toml # version = "0.2.0"
git commit -am "chore: bump version to 0.2.0"
git tag v0.2.0
git push origin master --tags
手动发布:
twine upload dist/*
# 先在测试仓库验证
twine upload --repository testpypi dist/*
pip install --index-url https://test.pypi.org/simple/ mutation-gate
升版本号
版本号在 pyproject.toml 中统一维护:
[project]
version = "0.2.0"
改完后重新构建即可,无需其他修改。
项目元数据(pyproject.toml 关键字段)
[build-system]
requires = ["hatchling>=1.21"] # 构建后端
build-backend = "hatchling.build"
[project]
name = "mutation-gate" # PyPI 包名
version = "0.1.0"
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
"click>=8.1,<9.0",
"prompt-toolkit>=3.0,<4.0",
]
[project.scripts]
mutation-gate = "mutation_gate.cli:main" # CLI 入口点
[tool.hatch.build.targets.wheel]
packages = ["src/mutation_gate"] # 只打包运行时代码
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mutation_gate-0.1.1.tar.gz.
File metadata
- Download URL: mutation_gate-0.1.1.tar.gz
- Upload date:
- Size: 378.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8f0d2045698d59d027a0f918a3089d6efe11bf3cb73c3237ba35c62f11b357ff
|
|
| MD5 |
ba0dcd30de147d936f43339268b4f6ca
|
|
| BLAKE2b-256 |
867370582b8fc53861294dcaa9b785f876b38703e23640a417f87568d11ba7a9
|
File details
Details for the file mutation_gate-0.1.1-py3-none-any.whl.
File metadata
- Download URL: mutation_gate-0.1.1-py3-none-any.whl
- Upload date:
- Size: 31.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f1cd00b1663b91a52d5709b7689ddf046b8a2e050bbb169fa73e33c303ca081c
|
|
| MD5 |
2e7502a3051c0578b0d02f4442032f98
|
|
| BLAKE2b-256 |
c31397549ab94125dd6681f066743efa58eac21061de81f37317e4839fa4771a
|