test-03 reproduction
Public source retained with the related article. Generated results, dependency directories, runtime storage, secrets, and oversized binary artifacts are intentionally excluded.
README
# TEST-03 mock-fortress experiment
This fixture supports the planned article *A Mock Fortress Tests a Call
Script*. It compares two tests for the same checkout quote under two controlled
changes:
- a behavior-preserving reorder of independent policy calls; and
- a production serializer defect that maps `tax_cents` from shipping.
The experiment asks what each test can reject. It does not claim that mocks,
ordered expectations, or unit tests are categorically harmful.
## Run it
Docker is the only host dependency.
```sh
./run.sh all
```
Each counterfactual can also run independently:
```sh
./run.sh clean
./run.sh reorder
./run.sh serializer
```
The runner builds a digest-pinned image, executes every expected pass and
failure, and returns non-zero if the crossed result is not reproduced. It
retains the exact command, expectation, exit code, duration, and console output
under `results/`.
## Expected matrix
| Mode | Mock fortress | Collaboration test | Observable JSON |
| --- | --- | --- | --- |
| Clean | pass | pass | expected quote |
| Policies reordered | fail | pass | byte-for-byte equal to clean |
| Serializer defect | pass | fail | `tax_cents` changes from `1800` to `500` |
The mock-fortress test constructs `BuildCheckoutQuote` directly with five
Mockery doubles. Every expectation is globally ordered. Its serializer double
returns the expected JSON instead of executing `JsonQuoteSerializer`.
The collaboration test registers the production bindings in Laravel's real
container, replaces only `ProductCatalogue`, resolves `BuildCheckoutQuote`, and
asserts the exact JSON produced by the real policies and serializer.
## Double map
| Double in fortress | Classification | Collaboration-test decision |
| --- | --- | --- |
| `ProductCatalogue` | external HTTP gateway | keep a fixed implementation of the production port |
| `DiscountPolicy` | owned deterministic policy | use the real implementation |
| `TaxPolicy` | owned deterministic policy | use the real implementation |
| `ShippingPolicy` | owned deterministic policy | use the real implementation |
| `QuoteSerializer` | owned output collaborator | use the real implementation |
| Laravel container | application composition | resolve through the real container |
The retained catalogue substitute returns only a product price. It neither
reimplements the policies nor supplies the final quote. The real HTTP adapter
still needs separate contract coverage; TEST-04 owns that question.
## Why both counterfactuals matter
The reorder is deliberately harmless. Tax and shipping depend on the same
already-discounted subtotal and destination, not on each other. `run.sh`
compares the complete clean and reordered output before accepting the green
collaboration test.
The serializer defect is deliberately observable. The quote total remains
`11300`, but the serialized `tax_cents` field changes from `1800` to `500`.
The fortress cannot see that production defect because its serializer never
runs.
Strict ordering can be correct when the order itself is a protocol, such as
commit-before-acknowledge. This fixture's independent policy calculations do
not have that contract.
## Toolchain and measurement boundary
The Dockerfile pins PHP and Composer images by version and digest.
`composer.lock` pins Laravel 13.20.0, PHPUnit 12.5.31, Mockery 1.6.12, and the
complete dependency graph. The runner records package versions and Composer's
advisory result with each run.
Durations include starting a disposable Docker container for each command.
They are reproduction metadata, not a benchmark of mocks versus real
collaborators.
Retained files
- .dockerignore
- bin/quote.php
- bin/versions.php
- composer.json
- composer.lock
- Dockerfile
- phpunit.xml
- README.md
- run.sh
- src/Catalogue/HttpProductCatalogue.php
- src/Catalogue/ProductCatalogue.php
- src/Checkout/BuildCheckoutQuote.php
- src/Checkout/CheckoutBindings.php
- src/Discount/DiscountPolicy.php
- src/Discount/ThresholdDiscountPolicy.php
- src/Quote/JsonQuoteSerializer.php
- src/Quote/Quote.php
- src/Quote/QuoteSerializer.php
- src/Shipping/FlatShippingPolicy.php
- src/Shipping/ShippingPolicy.php
- src/Tax/RegionalTaxPolicy.php
- src/Tax/TaxPolicy.php
- tests/CollaborationTest.php
- tests/FixedProductCatalogue.php
- tests/MockFortressTest.php