@homericintelligence/athena-opencode 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -17
- package/package.json +2 -2
- package/plugin.js +20 -5
- package/skills/TECHNICAL_ENGLISH.md +78 -0
- package/skills/_cli.py +33 -22
- package/skills/_plugin.json +1 -0
- package/skills/_support/docs/dependency-resolution.md +203 -0
- package/skills/_support/docs/policies/development.md +131 -0
- package/skills/_support/docs/policies/evidence-integrity.md +40 -0
- package/skills/_support/docs/principles/README.md +565 -0
- package/skills/_support/docs/principles/details/p001-kiss.md +114 -0
- package/skills/_support/docs/principles/details/p002-yagni.md +109 -0
- package/skills/_support/docs/principles/details/p003-dry.md +126 -0
- package/skills/_support/docs/principles/details/p004-solid.md +165 -0
- package/skills/_support/docs/principles/details/p005-modularity.md +123 -0
- package/skills/_support/docs/principles/details/p006-principle-of-least-astonishment.md +115 -0
- package/skills/_support/docs/principles/details/p007-subtraction-over-addition.md +113 -0
- package/skills/_support/docs/principles/details/p008-understand-before-subtracting.md +115 -0
- package/skills/_support/docs/principles/details/p009-general-mechanisms-over-special-cases.md +108 -0
- package/skills/_support/docs/principles/details/p010-scope-fidelity.md +117 -0
- package/skills/_support/docs/principles/details/p011-minimal-coherent-change.md +128 -0
- package/skills/_support/docs/principles/details/p012-evidence-before-modification.md +115 -0
- package/skills/_support/docs/principles/details/p013-avoid-hasty-abstractions.md +112 -0
- package/skills/_support/docs/principles/details/p014-preserve-unrequested-behavior.md +110 -0
- package/skills/_support/docs/principles/details/p015-architecture-conformance.md +124 -0
- package/skills/_support/docs/principles/details/p016-separation-of-concerns.md +125 -0
- package/skills/_support/docs/principles/details/p017-high-cohesion-low-coupling.md +130 -0
- package/skills/_support/docs/principles/details/p018-information-hiding.md +128 -0
- package/skills/_support/docs/principles/details/p019-explicit-contracts.md +134 -0
- package/skills/_support/docs/principles/details/p020-executable-architecture.md +130 -0
- package/skills/_support/docs/principles/details/p021-evolutionary-and-reversible-design.md +126 -0
- package/skills/_support/docs/principles/details/p022-test-behavior-not-implementation.md +129 -0
- package/skills/_support/docs/principles/details/p023-parameterized-table-driven-testing.md +129 -0
- package/skills/_support/docs/principles/details/p024-boundary-value-testing.md +128 -0
- package/skills/_support/docs/principles/details/p025-property-based-testing-for-invariants.md +133 -0
- package/skills/_support/docs/principles/details/p026-regression-before-repair.md +134 -0
- package/skills/_support/docs/principles/details/p027-deterministic-and-hermetic-tests.md +128 -0
- package/skills/_support/docs/principles/details/p028-test-failure-paths.md +133 -0
- package/skills/_support/docs/principles/details/p029-generalize-error-policy-preserve-specific-cause.md +131 -0
- package/skills/_support/docs/principles/details/p030-nearest-responsible-error-boundary.md +133 -0
- package/skills/_support/docs/principles/details/p031-propagate-rather-than-swallow.md +131 -0
- package/skills/_support/docs/principles/details/p032-handle-once-preserve-causality.md +137 -0
- package/skills/_support/docs/principles/details/p033-state-safe-failure-semantics.md +140 -0
- package/skills/_support/docs/principles/details/p034-fail-fast.md +132 -0
- package/skills/_support/docs/principles/details/p035-fail-secure-fail-closed.md +137 -0
- package/skills/_support/docs/principles/details/p036-graceful-degradation.md +137 -0
- package/skills/_support/docs/principles/details/p037-idempotency-before-retry.md +139 -0
- package/skills/_support/docs/principles/details/p038-bounded-retry.md +145 -0
- package/skills/_support/docs/principles/details/p039-bounded-waiting.md +151 -0
- package/skills/_support/docs/principles/details/p040-bounded-resources.md +138 -0
- package/skills/_support/docs/principles/details/p041-backpressure-and-load-shedding.md +141 -0
- package/skills/_support/docs/principles/details/p042-fault-isolation-bulkheads.md +140 -0
- package/skills/_support/docs/principles/details/p043-circuit-breakers.md +148 -0
- package/skills/_support/docs/principles/details/p044-atomicity-where-possible.md +141 -0
- package/skills/_support/docs/principles/details/p045-compensation-where-atomicity-is-impossible.md +163 -0
- package/skills/_support/docs/principles/details/p046-resumability.md +138 -0
- package/skills/_support/docs/principles/details/p047-observability-is-part-of-correctness.md +134 -0
- package/skills/_support/docs/principles/details/p048-secure-by-design.md +132 -0
- package/skills/_support/docs/principles/details/p049-secure-by-default.md +126 -0
- package/skills/_support/docs/principles/details/p050-least-privilege.md +123 -0
- package/skills/_support/docs/principles/details/p051-complete-mediation.md +124 -0
- package/skills/_support/docs/principles/details/p052-separation-of-duties.md +129 -0
- package/skills/_support/docs/principles/details/p053-validate-at-trust-boundaries.md +126 -0
- package/skills/_support/docs/principles/details/p054-defense-in-depth.md +135 -0
- package/skills/_support/docs/principles/details/p055-minimize-attack-surface.md +133 -0
- package/skills/_support/docs/principles/details/p056-secrets-stay-out-of-code-and-context.md +137 -0
- package/skills/_support/docs/principles/details/p057-supply-chain-integrity.md +135 -0
- package/skills/_support/docs/principles/details/p058-bounded-agent-authority.md +137 -0
- package/skills/_support/docs/principles/details/p059-data-is-not-instruction.md +130 -0
- package/skills/_support/docs/principles/details/p060-constrain-sub-agents.md +136 -0
- package/skills/_support/docs/principles/details/p061-separate-decision-from-high-impact-execution.md +131 -0
- package/skills/_support/docs/principles/details/p062-human-approval-for-irreversible-or-high-risk-actions.md +129 -0
- package/skills/_support/docs/principles/details/p063-requirement-to-code-traceability.md +116 -0
- package/skills/_support/docs/principles/details/p064-requirement-to-test-traceability.md +116 -0
- package/skills/_support/docs/principles/details/p065-verify-before-claiming-completion.md +131 -0
- package/skills/_support/docs/principles/details/p066-preserve-existing-work.md +114 -0
- package/skills/_support/docs/principles/details/p067-no-test-cheating.md +126 -0
- package/skills/_support/docs/principles/details/p068-no-validation-bypass.md +119 -0
- package/skills/_support/docs/principles/details/p069-independent-review-for-high-risk-changes.md +129 -0
- package/skills/_support/docs/principles/details/p070-code-health-must-not-regress.md +116 -0
- package/skills/_support/docs/principles/details/p071-consistency-over-personal-preference.md +117 -0
- package/skills/_support/docs/principles/details/p072-technical-evidence-over-preference.md +122 -0
- package/skills/_support/docs/principles/details/p073-optimize-only-with-evidence.md +123 -0
- package/skills/_support/docs/principles/details/p074-prefer-existing-mechanisms.md +121 -0
- package/skills/_support/docs/principles/details/p075-make-invalid-states-hard-to-represent.md +128 -0
- package/skills/_support/docs/principles/details/p076-parse-then-validate-then-operate.md +133 -0
- package/skills/_support/docs/principles/details/p077-separate-policy-from-mechanism.md +112 -0
- package/skills/_support/docs/principles/details/p078-single-source-of-truth.md +131 -0
- package/skills/_support/docs/principles/details/p079-explicit-ownership-and-lifetimes.md +124 -0
- package/skills/_support/docs/principles/details/p080-make-concurrency-deliberate.md +122 -0
- package/skills/_support/docs/principles/details/p081-forward-progress-with-safety.md +125 -0
- package/skills/_support/docs/principles/details/p082-design-for-cancellation.md +133 -0
- package/skills/_support/docs/principles/details/p083-irreversible-actions-last.md +124 -0
- package/skills/_support/docs/principles/details/p084-prefer-local-reasoning.md +131 -0
- package/skills/_support/docs/principles/details/p085-explicit-is-better-than-implicit.md +123 -0
- package/skills/_support/docs/principles/details/p086-readability-counts.md +113 -0
- package/skills/_support/docs/principles/details/p087-comments-explain-why-code-explains-what.md +120 -0
- package/skills/_support/docs/principles/details/p088-delete-dead-code.md +125 -0
- package/skills/_support/docs/principles/details/p089-delete-obsolete-configuration-and-dependencies.md +125 -0
- package/skills/_support/docs/principles/details/p090-prefer-negative-code.md +134 -0
- package/skills/_support/docs/principles/details/p091-test-driven-development.md +149 -0
- package/skills/_support/docs/review/README.md +63 -0
- package/skills/_support/docs/review/behavior-first-testing.md +78 -0
- package/skills/_support/docs/review/common.md +400 -0
- package/skills/_support/docs/review/design-docs.md +74 -0
- package/skills/_support/docs/review/issue-planning.md +247 -0
- package/skills/_support/docs/review/language-routing.md +141 -0
- package/skills/_support/docs/review/repository-scorecard.md +170 -0
- package/skills/advise/SKILL.md +108 -74
- package/skills/advise/scripts/list_retrievable_skills.py +20 -8
- package/skills/advise/scripts/resolve_knowledge_checkout.py +533 -0
- package/skills/brainstorm/SKILL.md +163 -127
- package/skills/change-review/SKILL.md +91 -71
- package/skills/change-review/references/scope-resolution.md +69 -46
- package/skills/change-review/scripts/resolve_scope.py +144 -84
- package/skills/finalize-plan/SKILL.md +205 -139
- package/skills/git-worktrees/SKILL.md +100 -80
- package/skills/git-worktrees/scripts/prepare_worktree.py +34 -15
- package/skills/issue-review/SKILL.md +136 -79
- package/skills/learn/SKILL.md +359 -192
- package/skills/myrmidon-swarm/SKILL.md +126 -86
- package/skills/plan-issue/SKILL.md +122 -81
- package/skills/pr-review/SKILL.md +184 -116
- package/skills/pr-review/references/criteria.md +61 -37
- package/skills/pr-review/references/delivery.md +277 -101
- package/skills/pr-review/references/evidence.md +346 -149
- package/skills/pr-review/references/prevalidated.md +93 -61
- package/skills/pr-review/scripts/collect_evidence.py +312 -162
- package/skills/pr-review/scripts/deliver_go.py +701 -0
- package/skills/pr-review/scripts/diff_context.py +34 -15
- package/skills/pr-review/scripts/materialize_snapshot.py +141 -130
- package/skills/pr-review/scripts/pr_identity.py +27 -15
- package/skills/pr-review/scripts/resolve_pr.py +77 -41
- package/skills/realign/SKILL.md +516 -0
- package/skills/realign/references/aislop-integration.md +215 -0
- package/skills/realign/references/architecture-and-structure.md +271 -0
- package/skills/realign/references/control-flow-and-errors.md +344 -0
- package/skills/realign/references/tests-dependencies-and-security.md +261 -0
- package/skills/realign/scripts/resolve_assessment.py +1525 -0
- package/skills/repo-review/SKILL.md +202 -131
- package/skills/simplify/SKILL.md +174 -0
- package/skills/systematic-debugging/SKILL.md +212 -192
- package/skills/systematic-debugging/scripts/repository_evidence.py +26 -8
- package/skills/test-driven-development/SKILL.md +126 -96
- package/skills/tidy/SKILL.md +104 -59
- package/skills/tidy/scripts/run_tidy.py +54 -6
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# P022 — Test Behavior, Not Implementation
|
|
2
|
+
|
|
3
|
+
## Definition
|
|
4
|
+
|
|
5
|
+
Assert the observable contract of the tested system. Do not assert private methods, data structures,
|
|
6
|
+
or interactions that the contract does not make necessary.
|
|
7
|
+
|
|
8
|
+
If a refactor preserves system behavior, the system behavior tests usually do not change.
|
|
9
|
+
|
|
10
|
+
**Aliases:** black-box-oriented testing, implementation-agnostic testing.
|
|
11
|
+
|
|
12
|
+
## Provenance
|
|
13
|
+
|
|
14
|
+
**Classification:** practitioner heuristic.
|
|
15
|
+
|
|
16
|
+
Consumer and provider contract testing is a related but different method. It is not an alias for
|
|
17
|
+
this heuristic.
|
|
18
|
+
|
|
19
|
+
Black-box testing began before unit test frameworks. Many test communities did not recommend tests
|
|
20
|
+
of implementation details. No one source gives this formulation.
|
|
21
|
+
|
|
22
|
+
## Decision rule
|
|
23
|
+
|
|
24
|
+
Assert what a caller or user can observe in the contract. When an internal interaction is part of
|
|
25
|
+
the contract, assert that interaction.
|
|
26
|
+
|
|
27
|
+
## How to apply
|
|
28
|
+
|
|
29
|
+
- Before you select an assertion, give a name to the scenario and specified result.
|
|
30
|
+
- Exercise a public or approved boundary at the smallest applicable level.
|
|
31
|
+
- Observe return values, durable state, emitted events, or specified side effects.
|
|
32
|
+
- Use fakes or stubs to control dependencies.
|
|
33
|
+
- Do not put call sequences that do not change contract behavior in the test.
|
|
34
|
+
- Keep structural tests only for specified constraints, for example dependency direction or
|
|
35
|
+
security.
|
|
36
|
+
|
|
37
|
+
## Diagram
|
|
38
|
+
|
|
39
|
+
```mermaid
|
|
40
|
+
flowchart LR
|
|
41
|
+
Contract["Consumer contract"] --> Scenario["Give scenario"]
|
|
42
|
+
Scenario --> Boundary["Exercise supported boundary"]
|
|
43
|
+
Boundary --> Observe["Observe result or side effect"]
|
|
44
|
+
Observe --> Assert["Assert necessary behavior"]
|
|
45
|
+
Refactor["Replace internal mechanics"] --> Assert
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Language examples
|
|
49
|
+
|
|
50
|
+
The two tests assert stable order without inspection of the sort implementation.
|
|
51
|
+
|
|
52
|
+
Python:
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
def order_records(records: list[tuple[str, int]]) -> list[tuple[str, int]]:
|
|
56
|
+
return sorted(records, key=lambda record: record[1])
|
|
57
|
+
|
|
58
|
+
def test_order_is_stable() -> None:
|
|
59
|
+
records = [("first", 2), ("second", 1), ("third", 2)]
|
|
60
|
+
assert order_records(records) == [("second", 1), ("first", 2), ("third", 2)]
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Rust:
|
|
64
|
+
|
|
65
|
+
```rust
|
|
66
|
+
fn order_records(records: &mut Vec<(&str, u32)>) {
|
|
67
|
+
records.sort_by_key(|record| record.1);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
#[test]
|
|
71
|
+
fn order_is_stable() {
|
|
72
|
+
let mut records = vec![("first", 2), ("second", 1), ("third", 2)];
|
|
73
|
+
order_records(&mut records);
|
|
74
|
+
assert_eq!(records, vec![("second", 1), ("first", 2), ("third", 2)]);
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Boundaries and tensions
|
|
79
|
+
|
|
80
|
+
A consumer contract gives observable behavior. An audit event, transaction boundary, or idempotency key
|
|
81
|
+
can be an observable obligation. A user can observe the result without access to that obligation.
|
|
82
|
+
|
|
83
|
+
Black-box system tests can be slow and have low diagnostic precision. Use more than one test level.
|
|
84
|
+
When the output format is the contract, keep assertions for the full output.
|
|
85
|
+
|
|
86
|
+
## Examples
|
|
87
|
+
|
|
88
|
+
### Positive application
|
|
89
|
+
|
|
90
|
+
A sort test supplies records and asserts specified order and stability. The test does not use sort
|
|
91
|
+
algorithm details or the temporary collection.
|
|
92
|
+
|
|
93
|
+
### Misuse or counterexample
|
|
94
|
+
|
|
95
|
+
A test asserts a private call sequence that is not part of the contract. A safe refactor puts two
|
|
96
|
+
internal steps in one step, and the test fails.
|
|
97
|
+
|
|
98
|
+
### Athena or agent workflow
|
|
99
|
+
|
|
100
|
+
A helper test asserts exit status, structured output, and file effects. It does not use private
|
|
101
|
+
function names or log sentences that are not part of the contract.
|
|
102
|
+
|
|
103
|
+
## Related principles
|
|
104
|
+
|
|
105
|
+
- [P023 — Parameterized / Table-Driven Testing](p023-parameterized-table-driven-testing.md)
|
|
106
|
+
- [P026 — Regression Before Repair](p026-regression-before-repair.md)
|
|
107
|
+
- [P027 — Deterministic and Hermetic Tests](p027-deterministic-and-hermetic-tests.md)
|
|
108
|
+
|
|
109
|
+
## References
|
|
110
|
+
|
|
111
|
+
### Source information
|
|
112
|
+
|
|
113
|
+
- [Fowler, "Mocks Aren't Stubs" (2007)](https://martinfowler.com/articles/mocksArentStubs.html)
|
|
114
|
+
gives an analysis of state verification, interaction verification, and refactor costs from coupled
|
|
115
|
+
expectations.
|
|
116
|
+
|
|
117
|
+
### Applicable information
|
|
118
|
+
|
|
119
|
+
- [Microsoft, ".NET unit testing best practices"](https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-best-practices)
|
|
120
|
+
recommends tests that use public methods only.
|
|
121
|
+
- [Testing Library, "Guiding Principles"](https://testing-library.com/docs/guiding-principles/)
|
|
122
|
+
recommends UI tests that follow software operation, not component internals.
|
|
123
|
+
|
|
124
|
+
### More information
|
|
125
|
+
|
|
126
|
+
- [Google Engineering Practices, "What to look for in a code review"](https://google.github.io/eng-practices/review/reviewer/looking-for.html)
|
|
127
|
+
tells reviewers to make sure that tests detect broken behavior and stay simple.
|
|
128
|
+
|
|
129
|
+
[Back to the engineering principles catalog](../README.md#p022)
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# P023 — Parameterized / Table-Driven Testing
|
|
2
|
+
|
|
3
|
+
## Definition
|
|
4
|
+
|
|
5
|
+
Put one behavior rule in one test procedure. Apply that rule to more than one named case with inputs, expected
|
|
6
|
+
results, and related context.
|
|
7
|
+
|
|
8
|
+
This structure uses one test procedure for its examples.
|
|
9
|
+
|
|
10
|
+
**Aliases:** data-driven tests, test tables, parameterized tests, theories.
|
|
11
|
+
|
|
12
|
+
## Provenance
|
|
13
|
+
|
|
14
|
+
**Classification:** established principle.
|
|
15
|
+
|
|
16
|
+
Test frameworks and language communities used data-driven tests before the tools available today. The name
|
|
17
|
+
is applicable to two forms. No one source started the method.
|
|
18
|
+
|
|
19
|
+
## Decision rule
|
|
20
|
+
|
|
21
|
+
When cases are different mainly because of data, use one clear test procedure. Give each case its
|
|
22
|
+
own name.
|
|
23
|
+
|
|
24
|
+
## How to apply
|
|
25
|
+
|
|
26
|
+
- Give each case a diagnostic name that gives the case condition.
|
|
27
|
+
- Store explicit expected results. Do not calculate them with production logic.
|
|
28
|
+
- Include usual, nondefault, empty, missing, rejected, and boundary cases.
|
|
29
|
+
- Keep setup and assertions small for each case. Use a different test for cases that apply a
|
|
30
|
+
different rule.
|
|
31
|
+
- Isolate mutable case data. Make each failure identify the specified case.
|
|
32
|
+
|
|
33
|
+
## Diagram
|
|
34
|
+
|
|
35
|
+
```mermaid
|
|
36
|
+
flowchart LR
|
|
37
|
+
Rule["One behavior rule"] --> Procedure["One test procedure"]
|
|
38
|
+
Cases["Named input and expected-result cases"] --> Procedure
|
|
39
|
+
Procedure --> Run["Run each case"]
|
|
40
|
+
Run --> Result{"Case passes?"}
|
|
41
|
+
Result -->|No| Name["Report specified case name"]
|
|
42
|
+
Result -->|Yes| More{"More cases?"}
|
|
43
|
+
More -->|Yes| Run
|
|
44
|
+
More -->|No| Success["Test completes"]
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Language examples
|
|
48
|
+
|
|
49
|
+
The two examples apply one normalization rule to the same named cases.
|
|
50
|
+
|
|
51
|
+
Python:
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
def normalize(value: str) -> str:
|
|
55
|
+
return value.strip().lower()
|
|
56
|
+
|
|
57
|
+
def test_normalize_cases() -> None:
|
|
58
|
+
cases = [("trim", " Yes ", "yes"), ("case", "NO", "no"), ("empty", " ", "")]
|
|
59
|
+
for name, given, expected in cases:
|
|
60
|
+
assert normalize(given) == expected, name
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Rust:
|
|
64
|
+
|
|
65
|
+
```rust
|
|
66
|
+
fn normalize(value: &str) -> String {
|
|
67
|
+
value.trim().to_lowercase()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
#[test]
|
|
71
|
+
fn normalize_cases() {
|
|
72
|
+
let cases = [("trim", " Yes ", "yes"), ("case", "NO", "no"), ("empty", " ", "")];
|
|
73
|
+
for (name, given, expected) in cases {
|
|
74
|
+
assert_eq!(normalize(given), expected, "{name}");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Boundaries and tensions
|
|
80
|
+
|
|
81
|
+
When cases use different workflows or many conditional fields, a large table can hide the test objective.
|
|
82
|
+
Do not put different integration scenarios in one loop only to remove lines.
|
|
83
|
+
|
|
84
|
+
Parameterization adds coverage for selected examples. It does not include all inputs. It does not
|
|
85
|
+
replace property tests or boundary analysis.
|
|
86
|
+
|
|
87
|
+
## Examples
|
|
88
|
+
|
|
89
|
+
### Positive application
|
|
90
|
+
|
|
91
|
+
A parser test uses one public operation for some named cases. Cases include a usual value,
|
|
92
|
+
whitespace, empty input, malformed syntax, and maximum length.
|
|
93
|
+
|
|
94
|
+
### Misuse or counterexample
|
|
95
|
+
|
|
96
|
+
One table contains flags that select different setup, invocation, and assertion branches. The test
|
|
97
|
+
loop becomes a second implementation that is not easy to understand.
|
|
98
|
+
|
|
99
|
+
### Athena or agent workflow
|
|
100
|
+
|
|
101
|
+
A validator uses named cases for accepted frontmatter, a missing field, an unknown field, and malformed
|
|
102
|
+
YAML. Each case uses one invocation and result check.
|
|
103
|
+
|
|
104
|
+
## Related principles
|
|
105
|
+
|
|
106
|
+
- [P022 — Test Behavior, Not Implementation](p022-test-behavior-not-implementation.md)
|
|
107
|
+
- [P024 — Boundary-Value Testing](p024-boundary-value-testing.md)
|
|
108
|
+
- [P025 — Property-Based Testing for Invariants](p025-property-based-testing-for-invariants.md)
|
|
109
|
+
|
|
110
|
+
## References
|
|
111
|
+
|
|
112
|
+
### Source information
|
|
113
|
+
|
|
114
|
+
- [Go project, "TableDrivenTests"](https://go.dev/wiki/TableDrivenTests)
|
|
115
|
+
records the Go practice of shared test logic with full named case data.
|
|
116
|
+
|
|
117
|
+
### Applicable information
|
|
118
|
+
|
|
119
|
+
- [pytest, "How to parametrize fixtures and test functions"](https://docs.pytest.org/en/stable/how-to/parametrize.html)
|
|
120
|
+
gives parameter sets, generated cases, fixtures, and per-case marks.
|
|
121
|
+
- [JUnit User Guide, "Parameterized Classes and Tests"](https://docs.junit.org/current/writing-tests/parameterized-classes-and-tests.html)
|
|
122
|
+
gives parameter sources, argument conversion, and named invocations.
|
|
123
|
+
|
|
124
|
+
### More information
|
|
125
|
+
|
|
126
|
+
- [Microsoft, ".NET unit testing best practices"](https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-best-practices)
|
|
127
|
+
shows the difference between duplicate test logic and named input and expected-result cases.
|
|
128
|
+
|
|
129
|
+
[Back to the engineering principles catalog](../README.md#p023)
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# P024 — Boundary-Value Testing
|
|
2
|
+
|
|
3
|
+
## Definition
|
|
4
|
+
|
|
5
|
+
Exercise values at and near transitions, limits, and equivalence partition edges. Defects frequently
|
|
6
|
+
occur where behavior changes.
|
|
7
|
+
|
|
8
|
+
Applicable cases include values less than, equal to, and more than a threshold. Also include zero,
|
|
9
|
+
one, empty, full, minimum, maximum, overflow, and rejected states.
|
|
10
|
+
|
|
11
|
+
**Aliases:** boundary value analysis, limit testing, edge testing.
|
|
12
|
+
|
|
13
|
+
## Provenance
|
|
14
|
+
|
|
15
|
+
**Classification:** established principle.
|
|
16
|
+
|
|
17
|
+
Boundary value analysis has a long history in software test literature and certification syllabi.
|
|
18
|
+
Evidence does not give one author as the first person to apply this analysis. Athena gives no first author.
|
|
19
|
+
|
|
20
|
+
## Decision rule
|
|
21
|
+
|
|
22
|
+
For each input partition or state transition with a material edge, select cases on each side and
|
|
23
|
+
at the edge. Include representations that can overflow or become empty.
|
|
24
|
+
|
|
25
|
+
## How to apply
|
|
26
|
+
|
|
27
|
+
- Use contracts, types, protocols, resource limits, and state transitions to find boundaries.
|
|
28
|
+
- When the contract has last accepted, first rejected, and transition values, test them.
|
|
29
|
+
- When evidence shows an interaction, include adjacent boundary combinations.
|
|
30
|
+
- After rejection, verify returned behavior and state preservation.
|
|
31
|
+
- When examples cannot include the boundary space, use generated or combinatorial methods.
|
|
32
|
+
|
|
33
|
+
## Diagram
|
|
34
|
+
|
|
35
|
+
```mermaid
|
|
36
|
+
flowchart LR
|
|
37
|
+
Contract["Contract or state transition"] --> Edge["Find material edge"]
|
|
38
|
+
Edge --> Less["Select a value less than the edge"]
|
|
39
|
+
Edge --> At["Select a value at the edge"]
|
|
40
|
+
Edge --> More["Select a value more than the edge"]
|
|
41
|
+
Less --> Verify["Verify result and state"]
|
|
42
|
+
At --> Verify
|
|
43
|
+
More --> Verify
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Language examples
|
|
47
|
+
|
|
48
|
+
The two examples verify the same values less than the minimum, at the limits, and more than the
|
|
49
|
+
maximum.
|
|
50
|
+
|
|
51
|
+
Python:
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
def accepts_batch(size: int) -> bool:
|
|
55
|
+
return 0 <= size <= 100
|
|
56
|
+
|
|
57
|
+
def test_batch_boundaries() -> None:
|
|
58
|
+
cases = [(-1, False), (0, True), (99, True), (100, True), (101, False)]
|
|
59
|
+
for size, expected in cases:
|
|
60
|
+
assert accepts_batch(size) is expected
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Rust:
|
|
64
|
+
|
|
65
|
+
```rust
|
|
66
|
+
fn accepts_batch(size: i32) -> bool {
|
|
67
|
+
(0..=100).contains(&size)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
#[test]
|
|
71
|
+
fn batch_boundaries() {
|
|
72
|
+
let cases = [(-1, false), (0, true), (99, true), (100, true), (101, false)];
|
|
73
|
+
for (size, expected) in cases {
|
|
74
|
+
assert_eq!(accepts_batch(size), expected);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Boundaries and tensions
|
|
80
|
+
|
|
81
|
+
Tests must use boundary values from correct partitions. Boundary tests do not replace
|
|
82
|
+
usual values between boundaries, semantic invariants, failure injection, or security
|
|
83
|
+
abuse cases.
|
|
84
|
+
|
|
85
|
+
Do not apply `n - 1`, `n`, and `n + 1` without domain analysis. A continuous, wrapped, or encoded
|
|
86
|
+
domain can make a different definition of adjacency necessary.
|
|
87
|
+
|
|
88
|
+
## Examples
|
|
89
|
+
|
|
90
|
+
### Positive application
|
|
91
|
+
|
|
92
|
+
A batch limit lets a request contain 100 items. Tests include 0, 1, 99, 100, and 101 items. The rejection test
|
|
93
|
+
shows that rejection cannot write only part of the batch.
|
|
94
|
+
|
|
95
|
+
### Misuse or counterexample
|
|
96
|
+
|
|
97
|
+
A test includes the maximum integer but ignores the API unit. The API applies its limit after UTF-8
|
|
98
|
+
encoding. Character count and byte count can be different.
|
|
99
|
+
|
|
100
|
+
### Athena or agent workflow
|
|
101
|
+
|
|
102
|
+
A bounded workflow test includes zero iterations, one iteration, the configured maximum, and one
|
|
103
|
+
iteration more than the maximum. That case must give a clear terminal failure.
|
|
104
|
+
|
|
105
|
+
## Related principles
|
|
106
|
+
|
|
107
|
+
- [P023 — Parameterized / Table-Driven Testing](p023-parameterized-table-driven-testing.md)
|
|
108
|
+
- [P025 — Property-Based Testing for Invariants](p025-property-based-testing-for-invariants.md)
|
|
109
|
+
- [P028 — Test Failure Paths, Not Just Success Paths](p028-test-failure-paths.md)
|
|
110
|
+
|
|
111
|
+
## References
|
|
112
|
+
|
|
113
|
+
### Source information
|
|
114
|
+
|
|
115
|
+
- [NIST, "Fault Classes and Error Detection in Specification Based Testing" (1998)](https://www.nist.gov/publications/fault-classes-and-error-detection-specification-based-testing)
|
|
116
|
+
examines specification conditions that can show specified fault classes.
|
|
117
|
+
|
|
118
|
+
### Applicable information
|
|
119
|
+
|
|
120
|
+
- [ISTQB Certified Tester Foundation Level Syllabus v4.0.1](https://istqb.org/wp-content/uploads/2024/11/ISTQB_CTFL_Syllabus_v4.0.1.pdf)
|
|
121
|
+
gives two-value and three-value analysis at and near equivalence partition boundaries.
|
|
122
|
+
|
|
123
|
+
### More information
|
|
124
|
+
|
|
125
|
+
- [NIST, "Software Fault Complexity and Implications for Software Testing"](https://www.nist.gov/publications/software-fault-complexity-and-implications-software-testing)
|
|
126
|
+
gives evidence for coverage of interactions in a small group of conditions.
|
|
127
|
+
|
|
128
|
+
[Back to the engineering principles catalog](../README.md#p024)
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# P025 — Property-Based Testing for Invariants
|
|
2
|
+
|
|
3
|
+
## Definition
|
|
4
|
+
|
|
5
|
+
Use properties that must hold for a set of input values. Generate many inputs and
|
|
6
|
+
reduce each failure to a small counterexample.
|
|
7
|
+
|
|
8
|
+
This method can help parsers, serializers, algorithms, transformations, protocols, and state
|
|
9
|
+
machines.
|
|
10
|
+
|
|
11
|
+
**Aliases:** generative property testing, QuickCheck-style testing.
|
|
12
|
+
|
|
13
|
+
## Provenance
|
|
14
|
+
|
|
15
|
+
**Classification:** established principle.
|
|
16
|
+
|
|
17
|
+
QuickCheck followed random tests and specification-based generators. Claessen and Hughes wrote the
|
|
18
|
+
2000 paper. It gave the library pattern of generators, properties, and shrinking.
|
|
19
|
+
|
|
20
|
+
## Decision rule
|
|
21
|
+
|
|
22
|
+
When an invariant gives correctness rules for more inputs than example cases, encode the invariant.
|
|
23
|
+
Generate accepted and rejected inputs from the domain. Preserve reproducible failures.
|
|
24
|
+
|
|
25
|
+
## How to apply
|
|
26
|
+
|
|
27
|
+
- Give a property such as round-trip equivalence, order, conservation, or a state
|
|
28
|
+
invariant.
|
|
29
|
+
- Make generators that represent the domain and include shapes with nested or constrained data.
|
|
30
|
+
- Give rejected combinations. Do not discard most generated inputs.
|
|
31
|
+
- Reduce each failure to a small counterexample. Add each counterexample that helps diagnosis to the
|
|
32
|
+
regression suite.
|
|
33
|
+
- Record seeds and control external state so each failure is reproducible.
|
|
34
|
+
|
|
35
|
+
## Diagram
|
|
36
|
+
|
|
37
|
+
```mermaid
|
|
38
|
+
flowchart LR
|
|
39
|
+
Property["Invariant"] --> Generator["Generate domain inputs"]
|
|
40
|
+
Generator --> Evaluate["Verify property"]
|
|
41
|
+
Evaluate --> Result{"Property holds?"}
|
|
42
|
+
Result -->|Yes| Budget{"All budgeted cases have results?"}
|
|
43
|
+
Budget -->|No| Generator
|
|
44
|
+
Budget -->|Yes| Success["Complete run"]
|
|
45
|
+
Result -->|No| Reduce["Reduce counterexample"]
|
|
46
|
+
Reduce --> Preserve["Preserve reproducible case"]
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Language examples
|
|
50
|
+
|
|
51
|
+
The two examples generate sequences of signed 32-bit integers with 0–99 elements and verify the
|
|
52
|
+
same reverse round-trip property.
|
|
53
|
+
|
|
54
|
+
Python:
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from hypothesis import given
|
|
58
|
+
from hypothesis import strategies as st
|
|
59
|
+
|
|
60
|
+
@given(st.lists(
|
|
61
|
+
st.integers(min_value=-(2**31), max_value=2**31 - 1),
|
|
62
|
+
min_size=0, max_size=99,
|
|
63
|
+
))
|
|
64
|
+
def test_reverse_round_trip(value: list[int]) -> None:
|
|
65
|
+
encoded = list(reversed(value))
|
|
66
|
+
assert list(reversed(encoded)) == value
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Rust:
|
|
70
|
+
|
|
71
|
+
```rust
|
|
72
|
+
use proptest::prelude::*;
|
|
73
|
+
|
|
74
|
+
proptest! {
|
|
75
|
+
#[test]
|
|
76
|
+
fn reverse_round_trip(value in proptest::collection::vec(any::<i32>(), 0..100)) {
|
|
77
|
+
let encoded: Vec<_> = value.iter().rev().copied().collect();
|
|
78
|
+
let decoded: Vec<_> = encoded.iter().rev().copied().collect();
|
|
79
|
+
prop_assert_eq!(decoded, value);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Boundaries and tensions
|
|
85
|
+
|
|
86
|
+
High case volume cannot correct a weak property or biased generator. Use property tests with named
|
|
87
|
+
examples, boundary cases, proofs, fuzz tests, and integration tests.
|
|
88
|
+
|
|
89
|
+
Do not copy the implementation into the oracle. A finite run without failures does not verify a
|
|
90
|
+
property in an unbounded domain.
|
|
91
|
+
|
|
92
|
+
## Examples
|
|
93
|
+
|
|
94
|
+
### Positive application
|
|
95
|
+
|
|
96
|
+
A serializer property generates accepted domain values. It verifies that decode after encode returns
|
|
97
|
+
an equivalent value. Each failure has a small, reproducible counterexample.
|
|
98
|
+
|
|
99
|
+
### Misuse or counterexample
|
|
100
|
+
|
|
101
|
+
A sort property verifies only output length. An implementation can return copies of one element and
|
|
102
|
+
pass this weak property.
|
|
103
|
+
|
|
104
|
+
### Athena or agent workflow
|
|
105
|
+
|
|
106
|
+
A parser helper generates accepted frontmatter maps with different key orders. The property verifies
|
|
107
|
+
the same normalized contract without undeclared file or network access.
|
|
108
|
+
|
|
109
|
+
## Related principles
|
|
110
|
+
|
|
111
|
+
- [P022 — Test Behavior, Not Implementation](p022-test-behavior-not-implementation.md)
|
|
112
|
+
- [P024 — Boundary-Value Testing](p024-boundary-value-testing.md)
|
|
113
|
+
- [P027 — Deterministic and Hermetic Tests](p027-deterministic-and-hermetic-tests.md)
|
|
114
|
+
|
|
115
|
+
## References
|
|
116
|
+
|
|
117
|
+
### Source information
|
|
118
|
+
|
|
119
|
+
- [Claessen and Hughes, "QuickCheck: A Lightweight Tool for Random Testing of Haskell Programs" (2000)](https://doi.org/10.1145/351240.351266)
|
|
120
|
+
gave the generator and property library design that many tools use.
|
|
121
|
+
|
|
122
|
+
### Applicable information
|
|
123
|
+
|
|
124
|
+
- [Hypothesis documentation, API reference](https://hypothesis.readthedocs.io/en/latest/reference/api.html)
|
|
125
|
+
gives generation, targeted exploration, stateful invariants, and shrinking controls.
|
|
126
|
+
|
|
127
|
+
### More information
|
|
128
|
+
|
|
129
|
+
- [Google XLS, "Exhaustive QuickCheck and fuzz tests"](https://google.github.io/xls/dslx_reference/#quickcheck)
|
|
130
|
+
shows the differences between property generation, exhaustive checks for small domains, and
|
|
131
|
+
coverage-guided fuzz tests.
|
|
132
|
+
|
|
133
|
+
[Back to the engineering principles catalog](../README.md#p025)
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# P026 — Regression Before Repair
|
|
2
|
+
|
|
3
|
+
## Definition
|
|
4
|
+
|
|
5
|
+
If safe defect reproduction is possible before implementation repair, add an automated test.
|
|
6
|
+
Make sure that the test fails for the reported cause.
|
|
7
|
+
|
|
8
|
+
After the repair, make sure that the test passes. Keep the test in the suite to detect recurrence.
|
|
9
|
+
|
|
10
|
+
**Aliases:** bug-reproduction test, failing regression test.
|
|
11
|
+
|
|
12
|
+
## Provenance
|
|
13
|
+
|
|
14
|
+
**Classification:** practitioner heuristic.
|
|
15
|
+
|
|
16
|
+
Automated unit test frameworks followed regression tests. Test-first defect repair is a method in
|
|
17
|
+
TDD and maintenance practice. No one source first gave this formulation.
|
|
18
|
+
|
|
19
|
+
## Decision rule
|
|
20
|
+
|
|
21
|
+
Before a repair, capture the smallest contract behavior that reproduces the defect. Make sure
|
|
22
|
+
that the unrepaired revision causes the test to fail.
|
|
23
|
+
|
|
24
|
+
## How to apply
|
|
25
|
+
|
|
26
|
+
- Reproduce the symptom at the nearest stable test level.
|
|
27
|
+
- Before implementation work, run the new test. Make sure that it fails for the reported cause.
|
|
28
|
+
- Use the smallest fixture that reproduces the defect.
|
|
29
|
+
- Preserve the defect condition.
|
|
30
|
+
- Repair the root cause. Then run the specified test and the applicable suite.
|
|
31
|
+
- Give the test a behavior name that continues to help after implementation changes.
|
|
32
|
+
|
|
33
|
+
## Diagram
|
|
34
|
+
|
|
35
|
+
```mermaid
|
|
36
|
+
flowchart LR
|
|
37
|
+
Report["Defect report"] --> Test["Create small behavior test"]
|
|
38
|
+
Test --> Red{"Fails for reported cause?"}
|
|
39
|
+
Red -->|No| Refine["Refine reproduction"]
|
|
40
|
+
Refine --> Test
|
|
41
|
+
Red -->|Yes| Repair["Repair root cause"]
|
|
42
|
+
Repair --> Green{"Specified test passes?"}
|
|
43
|
+
Green -->|No| Repair
|
|
44
|
+
Green -->|Yes| Suite["Run applicable suite"]
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Language examples
|
|
48
|
+
|
|
49
|
+
The two examples preserve the same empty-input regression after the mean calculation repair.
|
|
50
|
+
|
|
51
|
+
Python:
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
def mean(values: list[float]) -> float | None:
|
|
55
|
+
if not values:
|
|
56
|
+
return None
|
|
57
|
+
return sum(values) / len(values)
|
|
58
|
+
|
|
59
|
+
def test_empty_input_returns_none() -> None:
|
|
60
|
+
assert mean([]) is None
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Rust:
|
|
64
|
+
|
|
65
|
+
```rust
|
|
66
|
+
fn mean(values: &[f64]) -> Option<f64> {
|
|
67
|
+
if values.is_empty() {
|
|
68
|
+
return None;
|
|
69
|
+
}
|
|
70
|
+
Some(values.iter().sum::<f64>() / values.len() as f64)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
#[test]
|
|
74
|
+
fn empty_input_returns_none() {
|
|
75
|
+
assert_eq!(mean(&[]), None);
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Boundaries and tensions
|
|
80
|
+
|
|
81
|
+
Safe reproduction is not possible in each case. Production containment, destructive failures,
|
|
82
|
+
nondeterministic races, or unavailable dependencies can make safe mitigation necessary before reproduction.
|
|
83
|
+
When reproduction with the production dependency is not safe, use a model-based reproduction.
|
|
84
|
+
|
|
85
|
+
Do not write a test that copies the defective implementation or depends on an accidental symptom. A
|
|
86
|
+
test added only after repair gives weaker evidence. No evidence shows its sensitivity to the
|
|
87
|
+
reported defect.
|
|
88
|
+
|
|
89
|
+
A regression test is RED on the unrepaired revision and GREEN after repair. A characterization
|
|
90
|
+
test starts GREEN and records behavior before a behavior-preserving refactor. These tests have
|
|
91
|
+
related but different objectives.
|
|
92
|
+
|
|
93
|
+
## Examples
|
|
94
|
+
|
|
95
|
+
### Positive application
|
|
96
|
+
|
|
97
|
+
A parser report includes one malformed input. A small test of the public API first reproduces the
|
|
98
|
+
exception. The test passes after the parser returns the specified structured error.
|
|
99
|
+
|
|
100
|
+
### Misuse or counterexample
|
|
101
|
+
|
|
102
|
+
A developer adds a test after the code change. The test passes on each revision. It does not give
|
|
103
|
+
evidence of regression sensitivity.
|
|
104
|
+
|
|
105
|
+
### Athena or agent workflow
|
|
106
|
+
|
|
107
|
+
An agent records the failed command and output. The agent makes the smallest necessary repair. Then,
|
|
108
|
+
the agent runs that test again. If the test passes, the agent runs the repository gate.
|
|
109
|
+
|
|
110
|
+
## Related principles
|
|
111
|
+
|
|
112
|
+
- [P021 — Evolutionary and Reversible Design](p021-evolutionary-and-reversible-design.md)
|
|
113
|
+
- [P022 — Test Behavior, Not Implementation](p022-test-behavior-not-implementation.md)
|
|
114
|
+
- [P027 — Deterministic and Hermetic Tests](p027-deterministic-and-hermetic-tests.md)
|
|
115
|
+
- [P091 — Test-Driven Development](p091-test-driven-development.md)
|
|
116
|
+
|
|
117
|
+
## References
|
|
118
|
+
|
|
119
|
+
### Source information
|
|
120
|
+
|
|
121
|
+
- [Beck, *Test-Driven Development: By Example* (2002)](https://www.pearson.com/en-us/subject-catalog/p/Beck-Test-Driven-Development-By-Example/P200000009421/9780321146533)
|
|
122
|
+
gives a widely used test-first cycle that also applies to defect repair.
|
|
123
|
+
|
|
124
|
+
### Applicable information
|
|
125
|
+
|
|
126
|
+
- [Google Engineering Practices, "Small CLs"](https://google.github.io/eng-practices/review/developer/small-cls.html)
|
|
127
|
+
gives pre-refactor guidance for tests of behavior changes and missing behavioral coverage.
|
|
128
|
+
|
|
129
|
+
### More information
|
|
130
|
+
|
|
131
|
+
- [Microsoft, ".NET unit testing best practices"](https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-best-practices)
|
|
132
|
+
gives information about regression protection and repeatable, self-checking tests.
|
|
133
|
+
|
|
134
|
+
[Back to the engineering principles catalog](../README.md#p026)
|