agentleFS
luabaggluabagg/agent-skills/skills/testing-business-rules/SKILL.md

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.

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
  1. Distinctive:

    Keep regressions that protect valid rules and add detection, including obvious mistakes, manually detectable bugs, and bad decisions.

    line 41
  2. Distinctive:

    Use a public function or module for local rules.

    line 45
  3. Distinctive:

    Use multiple assertions when they jointly establish one outcome.

    line 58
  4. Distinctive:

    Never delete by title: rename a poorly named security test.

    line 68

≈ “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.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

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 forReject or reshape
Domain behavior, API/provider contracts, numeric or ordering guaranteesAssertions that merely restate the implementation
Validation, authorization, privacy, data integrityInput permutations with no distinct risk
Idempotency, retries, discard policies, persistence and queue integrationPrivate helper calls or incidental call order
Observed regressions, including obvious mistakesDuplicate coverage with no additional failure detection
Boundaries with a named consequenceSnapshots 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:

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.