Skip to content

Commit 1ba7201

Browse files
sedat4rasclaude
andcommitted
docs: add plugin testing guide
Closes #937 Add a new page (docs/customization/testing_plugins.md) explaining how to write a test suite for a Commitizen plugin. Covers: - Testing bump_pattern / bump_map with bump.find_increment - Testing changelog_pattern and commit_parser with regex matching - Testing message() output against expected commit strings - Testing schema validation Also adds the page to the nav in mkdocs.yml under Customization. Co-authored-by: Claude <noreply@anthropic.com>
1 parent 984bb62 commit 1ba7201

File tree

2 files changed

+157
-0
lines changed

2 files changed

+157
-0
lines changed
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
# Testing your Commitizen plugin
2+
3+
Adding a test suite to your plugin helps prevent accidental regressions when you update
4+
commit rules, regex patterns, or changelog templates. This guide shows how to test the
5+
most common plugin behaviors using [pytest](https://docs.pytest.org/).
6+
7+
## Setup
8+
9+
Install the testing dependencies in your plugin project:
10+
11+
```bash
12+
pip install commitizen pytest
13+
```
14+
15+
## Testing commit message rules
16+
17+
### Testing `bump_pattern` and `bump_map`
18+
19+
Use `commitizen.bump.find_increment` to verify that your regex correctly maps commit
20+
messages to the expected version increment (`MAJOR`, `MINOR`, `PATCH`, or `None`).
21+
22+
```python title="tests/test_my_plugin.py"
23+
import pytest
24+
from commitizen import bump
25+
from commitizen.git import GitCommit
26+
27+
from my_plugin import MyCommitizen # replace with your plugin import
28+
29+
30+
def make_commits(*messages: str) -> list[GitCommit]:
31+
return [GitCommit(rev="abc123", title=msg) for msg in messages]
32+
33+
34+
@pytest.mark.parametrize(
35+
("messages", "expected"),
36+
[
37+
# patch — bug fixes should produce a PATCH bump
38+
(["fix: correct off-by-one error"], "PATCH"),
39+
# minor — new features should produce a MINOR bump
40+
(["feat: add dark mode"], "MINOR"),
41+
# major — breaking changes should produce a MAJOR bump
42+
(["feat!: rename public API"], "MAJOR"),
43+
# no relevant commits — no bump
44+
(["chore: update CI config"], None),
45+
],
46+
)
47+
def test_bump_increment(messages, expected):
48+
commits = make_commits(*messages)
49+
result = bump.find_increment(
50+
commits,
51+
regex=MyCommitizen.bump_pattern,
52+
increments_map=MyCommitizen.bump_map,
53+
)
54+
assert result == expected
55+
```
56+
57+
### Testing `changelog_pattern` and `commit_parser`
58+
59+
Verify that only relevant commits appear in the changelog and that the parser
60+
extracts fields (type, scope, message) correctly.
61+
62+
```python title="tests/test_changelog_rules.py"
63+
import re
64+
65+
from my_plugin import MyCommitizen
66+
67+
68+
@pytest.mark.parametrize(
69+
("message", "should_match"),
70+
[
71+
("feat(api): add pagination", True),
72+
("fix: handle null pointer", True),
73+
("chore: bump dev dependency", False),
74+
("docs: update README", False),
75+
],
76+
)
77+
def test_changelog_pattern(message, should_match):
78+
pattern = re.compile(MyCommitizen.changelog_pattern)
79+
assert bool(pattern.match(message)) is should_match
80+
81+
82+
@pytest.mark.parametrize(
83+
("message", "expected_groups"),
84+
[
85+
(
86+
"feat(api): add pagination",
87+
{"change_type": "feat", "scope": "api", "message": "add pagination"},
88+
),
89+
(
90+
"fix: handle null pointer",
91+
{"change_type": "fix", "scope": None, "message": "handle null pointer"},
92+
),
93+
],
94+
)
95+
def test_commit_parser(message, expected_groups):
96+
pattern = re.compile(MyCommitizen.commit_parser)
97+
match = pattern.match(message)
98+
assert match is not None
99+
for key, value in expected_groups.items():
100+
assert match.group(key) == value
101+
```
102+
103+
### Testing `message()` output
104+
105+
Ensure your `message()` method produces the correct commit string from user answers.
106+
107+
```python title="tests/test_message.py"
108+
from commitizen.config import BaseConfig
109+
110+
from my_plugin import MyCommitizen
111+
112+
113+
def test_message_with_scope():
114+
cz = MyCommitizen(BaseConfig())
115+
msg = cz.message({"type": "feat", "scope": "api", "subject": "add pagination"})
116+
assert msg == "feat(api): add pagination"
117+
118+
119+
def test_message_without_scope():
120+
cz = MyCommitizen(BaseConfig())
121+
msg = cz.message({"type": "fix", "scope": "", "subject": "handle null pointer"})
122+
assert msg == "fix: handle null pointer"
123+
```
124+
125+
## Testing schema validation
126+
127+
If your plugin overrides `schema_pattern()`, test that valid and invalid commit
128+
messages are accepted and rejected as expected.
129+
130+
```python title="tests/test_schema.py"
131+
import re
132+
133+
from my_plugin import MyCommitizen
134+
135+
136+
def test_valid_commit_passes_schema():
137+
pattern = re.compile(MyCommitizen().schema_pattern())
138+
assert pattern.match("feat(api): add pagination")
139+
140+
141+
def test_invalid_commit_fails_schema():
142+
pattern = re.compile(MyCommitizen().schema_pattern())
143+
assert not pattern.match("random text without type")
144+
```
145+
146+
## Running the tests
147+
148+
```bash
149+
pytest tests/ -v
150+
```
151+
152+
## See also
153+
154+
- [Customizing through a Python class](python_class.md) — full plugin API reference
155+
- [Third-Party Commitizen Plugins](../third-party-plugins/about.md) — examples of published plugins
156+
- [Commitizen's own test suite](https://github.com/commitizen-tools/commitizen/tree/master/tests) — for more advanced testing patterns

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ nav:
5959
- Advanced Customization:
6060
- Customize via config file: "customization/config_file.md"
6161
- Customized Python Class: "customization/python_class.md"
62+
- Testing Plugins: "customization/testing_plugins.md"
6263
- Changelog Template: "customization/changelog_template.md"
6364
- Tutorials:
6465
- Commit Message Best Practices: "tutorials/writing_commits.md"

0 commit comments

Comments
 (0)