Skip to main content

多语言变异测试质量门禁 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 生成覆盖率报告,再传给 runcheck

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mutation_gate-0.1.1.tar.gz (378.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mutation_gate-0.1.1-py3-none-any.whl (31.8 kB view details)

Uploaded Python 3

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

Hashes for mutation_gate-0.1.1.tar.gz
Algorithm Hash digest
SHA256 8f0d2045698d59d027a0f918a3089d6efe11bf3cb73c3237ba35c62f11b357ff
MD5 ba0dcd30de147d936f43339268b4f6ca
BLAKE2b-256 867370582b8fc53861294dcaa9b785f876b38703e23640a417f87568d11ba7a9

See more details on using hashes here.

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

Hashes for mutation_gate-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 f1cd00b1663b91a52d5709b7689ddf046b8a2e050bbb169fa73e33c303ca081c
MD5 2e7502a3051c0578b0d02f4442032f98
BLAKE2b-256 c31397549ab94125dd6681f066743efa58eac21061de81f37317e4839fa4771a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page