| Property | Value |
|---|---|
| Category | Reproducibility (JustDummies.Reproducibility) |
| Severity | 🟠 Warning |
| Enabled by default | Yes |
A type initializer runs once, lazily, when the first test touches the type. A value drawn there is therefore drawn under whatever ambient context that particular test happened to have pinned — and then shared, unchanged, by every other test in the class.
Three consequences follow, none of them visible:
- the value never varies between runs, so the arbitrary-by-default property that surfaces a test secretly depending on one particular value is switched off;
- the tests become order-dependent — a test can pass because the value was drawn under a sibling’s seed, and start failing when the suite is reordered or filtered;
- no reported seed replays it, because the draw belongs to whichever test ran first, not to the one that failed.
Store the generator in the static field and call Generate() where the value is needed. The random source is resolved at Generate() time, never at construction, so a shared generator is safe and idiomatic — only a shared value is not.
Noncompliant
private static readonly string Tenant = Any.String().NonEmpty().Generate(); // JD009: one draw for the whole suite
Compliant
private static readonly IAny<string> Tenant = Any.String().NonEmpty();
// ... per test:
string tenant = Tenant.Generate();
What it does not flag
- A static field holding the generator — the compliant shape, and explicitly safe.
- A draw in an instance field initializer or constructor: that is JD007’s subject when the class is
[Reproducible], and outside its scope otherwise. - A draw from an isolated
Any.WithSeed(...)context, or a generator reached through a local or field rather than written inline fromAny.
A deliberately process-wide constant — a tenant id no test is coupled to — is a legitimate reading of the noncompliant shape. The hazard analysis still holds, so the rule reports it; suppress it at the site if that is genuinely what you want.