Skip to content

docs(examples): add a hand-written contract tests example for the API-Only TranscriberJ - #90

Merged
Arc-E-Tect merged 3 commits into
mainfrom
feat/hand-written-contract-tests-example
Sep 18, 2026
Merged

Arc-E-Tect merged 3 commits into
mainfrom
feat/hand-written-contract-tests-example

Conversation

@Arc-E-Tect

Copy link
Copy Markdown
Owner

A Spring Boot 4.1.1 refunds service under examples/api-only-transcriberj/hand-written-contract-tests, with contract tests built on the classes TranscriberJ 0.3.3 generates, including where the generator stops.

What is in it

  • The contract, built by the Publisher in the example. POST /orders/{orderId}/refunds answers with 201, 400, 404 or 422.
    • The request body RefundRequestV1 is a oneOf with inline branches, so its body(...) and fields(...) are generated to throw. The report says so and gives the remedy.
    • A refund must go back the way the order was paid, which the schema cannot say. So a request can be valid against the schema and still get a 422.
  • The service is hand-written and never imports a generated class.
  • RefundRequests: the request body, written by hand in the generated package in the test source set.
    • It uses ContractJson and the generated constraint constants.
    • It types only what no generated class holds: the branch member names and the destination values.
  • RefundRequestsTest, 4 guards:
    • pinned to RefundRequestV1.FRAGMENT_SHA256;
    • the degraded method still throws;
    • the sample values satisfy the generated constraints;
    • the exact JSON written.
  • CreateRefundContractTest, 4 contract tests: one per response. Each checks status and content type against CreateRefundOperation and the fields against the generated RefundV1Docs / ProblemV1Docs.responseFields().
  • RefundsTest, 15 behaviour tests: every invalid input and every business rule, as scenarios.
  • Coverage: JaCoCo with a 90% gate on the service's code; it measures 98.8%. The generated classes are excluded by their annotation.
  • The README has an IMPORTANT box: the code lives in the generated package, and the project is responsible for whatever it types.
  • CI: a workflow of its own, example-api-only-transcriberj-hand-written-contract-tests-build.yml, runs ./gradlew check. actionlint is clean.

Verified on 0.3.3

  • ./gradlew check passes: 23 tests.
  • Shape drift is caught: giving the service's problem document an undocumented member fails all three error-response tests.
  • Both README "Try it" steps were run:
    • removing maximum breaks compilation at AmountV1.MAXIMUM;
    • renaming cardLast4 leaves every contract test passing, and only the hash guard fails.
  • The remedy (naming the branches) was run too:
    • the guard stops compilation;
    • after deleting the hand-written body, the contract tests use the generated CardRefundV1.body(...) and BankAccountRefundV1.body(...) from their own package, and check passes.

The tutorial that walks through this example is in the API repository, docs/guides/hand-written-contract-tests/, in its own PR.

Writing this example led to API #25 (the oneOf fixes, released as 0.3.3) and #26 (the README section on hand-written code).

…-Only TranscriberJ

A refunds service whose request body is a oneOf with inline branches,
which the generator cannot write, and whose 422 comes from a business
rule the schema cannot carry. The request body is written by hand in
the generated package from the generated constants, pinned to its
fragment's hash; one contract test per response checks the shape with
the generated REST Docs descriptors; every invalid input and rule is a
behaviour test. A workflow of its own runs check on every change.
@Arc-E-Tect
Arc-E-Tect merged commit 916c1e0 into main Sep 18, 2026
1 check passed
@Arc-E-Tect
Arc-E-Tect deleted the feat/hand-written-contract-tests-example branch September 18, 2026 13:01
Arc-E-Tect added a commit to Arc-E-Tect/SoftwareEngineeringDoneRight-API that referenced this pull request Sep 18, 2026
…ts (#27)

A guide in `docs/guides/hand-written-contract-tests/`, with an overview,
a tutorial, a Claude Code prompt and a Codex prompt, for the contract
tests the TranscriberJ cannot generate.

## What it covers

- **Where the generated tree stops.** Constraints are constants, not
checks. Field descriptions are a projection. Some constructs degrade to
methods that throw.
- **What you still have when a method refuses:** provenance, the
operation's path, statuses and content types, constraint constants, and
the response side in full.
- **Where hand-written code goes, as a design decision** (IMPORTANT
box): in the generated package, in the test source set. The
package-private members it reaches, `ContractJson` among them, are
regenerated every build and are not a published API.
- **What you own when you write it:** the values no generated class
holds, and four duties that follow from typing them.
- **How many tests, and why:** one contract test per response the
contract lists, checking only shape. Every invalid input and business
rule goes in behaviour tests, as scenarios.
- **A worked example:** a `oneOf` with inline branches plus a
business-rule 422. The hand-written body sits next to the generated
constants it draws on, and the assertions use the generated
error-response descriptors.
- **When the contract changes underneath:** a removed constant breaks
compilation at the line; a renamed member is caught only by the hash
guard.
- **The remedy:** name the branches. The guard fires, and the generated
bodies take over.

## Verified

- The tutorial's snippets are expanded by a script from the Library
example's files, generated sources, report and scenario runs, all on
TranscriberJ 0.3.3.
- Regenerating it after the 0.3.3 release gave byte-identical output.
- The example PR is Arc-E-Tect/SoftwareEngineeringDoneRight-Library#90.
- All AsciiDoc files render without warnings, and every link and anchor
resolves.

## Also

- `docs/README.adoc`: a row in the Guides table.
- The TranscriberJ README's "What this cannot do" section links to the
guide. It links back to the #26 sections.
@Arc-E-Tect

Copy link
Copy Markdown
Owner Author

🎉 This PR is included in version 1.0.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@Arc-E-Tect

Copy link
Copy Markdown
Owner Author

🎉 This PR is included in version 1.0.2 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@Arc-E-Tect

Copy link
Copy Markdown
Owner Author

🎉 This PR is included in version 0.2.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@Arc-E-Tect

Copy link
Copy Markdown
Owner Author

🎉 This PR is included in version 1.0.2 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@Arc-E-Tect

Copy link
Copy Markdown
Owner Author

🎉 This PR is included in version 1.0.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant