testing-business-rules
Skill3 starsChanged 3 months agoMITView on GitHub
Use when adding, reviewing, or deleting tests, deciding whether a function needs coverage, or when a suite enumerates branches, signs, empty values, or implementation steps without naming the behavior at risk.
In this repository9 other files it gives its agents.
- AGENTS.mdAGENTS.md
- agentfolio-operatorSkill
- branch-portSkill
- code-commentsSkill
- code-namingSkill
- cognitive-refactorSkill
- memory-palaceSkill
- natural-copy-editingSkill
- thorough-pr-reviewSkill
The file
We split this skill into the rules it gives an agent
4 rules. About 0 are common, 4 are distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 41
Keep regressions that protect valid rules and add detection, including obvious mistakes, manually detectable bugs, and bad decisions.
- Distinctive: line 45
Use a public function or module for local rules.
- Distinctive: line 58
Use multiple assertions when they jointly establish one outcome.
- Distinctive: line 68
Never delete by title: rename a poorly named security test.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Testing Business Rules
A test earns its place by protecting a meaningful behavior or contract, not by demonstrating today's implementation. A rule can be a product decision, a technical guarantee, or a consumer expectation.
Quick reference
| Keep coverage for | Reject or reshape |
| Domain behavior, API/provider contracts, numeric or ordering guarantees | Assertions that merely restate the implementation |
| Validation, authorization, privacy, data integrity | Input permutations with no distinct risk |
| Idempotency, retries, discard policies, persistence and queue integration | Private helper calls or incidental call order |
| Observed regressions, including obvious mistakes | Duplicate coverage with no additional failure detection |
| Boundaries with a named consequence | Snapshots that freeze incidental output |
Currency rounding can be a contract even when it uses simple arithmetic. Coverage metrics reveal gaps; they do not justify tests.
Procedure
1. Name the rule before writing the test
Record these in the test plan or review, not as boilerplate comments:
Rule: an empty tenant ID must never grant access to another tenant's records.
Established in: tenant-isolation security contract.
Failure: a caller reads another tenant's private records.Find evidence in requirements, API documentation, callers, history, or incidents, not current output alone. Missing evidence requires investigation with owners and consumers, not coverage removal. Temporary characterization tests can support legacy refactoring; label unconfirmed assumptions instead of declaring permanent contracts.
2. Find the coverage gap
Identify the wrong behavior this test would catch. Compare failure modes, not lines executed: happy-path coverage does not cover an authorization bypass.
Keep regressions that protect valid rules and add detection, including obvious mistakes, manually detectable bugs, and bad decisions.
3. Choose the smallest honest boundary
Use a public function or module for local rules. Use focused integration tests for collaboration, serialization, persistence, or queue guarantees. Use route/full-flow tests for behavior smaller tests cannot establish.
Prefer fast, deterministic real dependencies. Use a maintained fake when real dependencies are costly or unavailable; use stubs or mocks for controlled responses or contract-relevant interactions. Double at the existing dependency seam. Internal versus external is not the deciding factor: never replace the behavior or collaboration this test claims to verify.
A mocked database cannot prove transaction semantics. A mocked billing service cannot prove duplicate-charge prevention. Exercise the relevant production collaboration and verify doubles against real contracts separately. Keep tests isolated from live services; control clocks, randomness, and asynchronous completion instead of sleeping.
4. Write one focused behavior per test
Name the condition and promised outcome:
- Weak:
handles empty input - Better:
denies cross-tenant access when the tenant ID is empty
Use multiple assertions when they jointly establish one outcome. Use named parameterized cases for meaningful variants of one rule. Choose distinct, non-default values to expose ignored or swapped inputs; include zero, negative, empty, and boundary values when they challenge the contract.
When outcomes exclude each other, assert that the other outcome is absent. A test that checks only that the item expired still passes when the code also fulfills it. When a change adds an outcome, add its absence check to each existing test that expects no outcome. When a change moves a case from one outcome to another, name both in the test: expires, not fulfills, once the re-read cap is reached.
Assert observable results, state, or contractual interactions. Derive expected values independently of production logic. Avoid private structure and call order unless order itself is the guarantee. Names should explain arrange/act/assert; comments explain only non-obvious reasons.
5. Verify, then prune
Observe new tests fail for the intended missing behavior, then pass with the implementation. Check that existing tests would reject a plausible rule-breaking change. Run focused tests and relevant integration tests; report gaps.
Never delete by title: rename a poorly named security test. Remove a test only if it protects no valid contract or another test detects the same failure mode. Verify that conclusion first. Preserve distinct integration risks even when local tests cover the rule.
Report
Summarize by rule, not every parameterized row:
Protects: <rule; evidence; failure consequence>
Boundary: <function | module | integration | route/task; why; doubles>
Changed: <added/kept/renamed/removed; equivalent coverage for removals>
Verified: <commands and results; gaps or unconfirmed assumptions>Google guidance
This is a local policy informed by Google's Testing on the Toilet, not a formal Google standard:
- Test Behavior, Not Implementation: public contracts survive implementation changes, including simple arithmetic APIs.
- Test Behaviors, Not Methods: separate behaviors, not one test per method or assertion.
- Don't Overuse Mocks: prefer real dependencies or fakes when practical; mocks can drift and obscure intent.
- Just Say No to More End-to-End Tests: related Google Testing Blog guidance on fast, reliable unit tests and focused integration tests.
- Choosing Values for Robust Tests: distinct, non-default inputs and meaningful boundary cases expose false positives.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

