· budding · gradle, testing, modularisation
testFixtures share fakes between modules without shipping them
The java-test-fixtures plugin gives a module a third source set for fakes and builders. Other modules' tests can use it, and it stays out of the production jar.
The gap
I kept seeing testFixtures(project(...)) in our modules' test dependencies and couldn't say what it actually published, who could use it, or why the fakes didn't just live in main.
The pieces
- The
java-test-fixturesplugin adds asrc/testFixtures/source set to a module. - Code in there can see the module's own
maincode. - Another module's tests use it with
testImplementation(testFixtures(project(":pricing"))). - Libraries the fixtures themselves need go in
testFixturesApi(...)ortestFixturesImplementation(...). That's the same split as in A green build doesn't prove implementation() is right.
The click
Test fixtures are a small extra library, published next to the real one and used only by tests. The fake for an interface sits in the same module as the interface, so when the interface changes, the fake breaks there, once, and not in every module's test folder.
How I checked it
In the same Gradle 8.14.3 project as the api() card, pricing has FakePricing in src/testFixtures/:
checkout's tests compile againstFakePricing.checkout's main code referencingFakePricingfails witherror: cannot find symbol.pricing.jarcontains onlyPricing.class.FakePricing.classis in a separatepricing-test-fixtures.jar.
This was on plain JVM modules. Android library modules switch test fixtures on through the Android Gradle plugin, which I haven't checked here.
The project and a script that reruns it are in this site's repository.
Check yourself
Can production code in checkout use FakePricing?
No. Test fixtures are only on the consumer's test classpath, so main code fails with cannot find symbol.
Does the fake end up in the production jar?
No. It goes into a separate -test-fixtures jar.
Where does a library that only the fakes need belong?
In the providing module, under testFixturesImplementation(...), or testFixturesApi(...) if consumers' tests need to see it too.