JustDummies

Just dummies — but seriously powerful ones.

Documentation sections

JustDummies.Xunit

The xUnit v3 adapter. It contributes exactly one thing — a [Reproducible] attribute — and that one thing removes the need to wrap any test body in Any.Reproducibly.

Install

dotnet add package JustDummies.Xunit

It depends on JustDummies and on xUnit v3.

The whole surface

ReproducibleAttribute, with a settable Seed. That is all of it — the adapter is deliberately thin, because everything it needs already exists in the library (ADR-0018 opens in a new tab).

Using it

public sealed class OrderTests {

    [Fact, Reproducible]
    public void A_20_percent_discount_takes_a_fifth_off_the_order() {
        // Arrange
        string anyReference = Any.String().StartingWith("ORD-").WithLength(12).Generate();
        string anyCustomer  = Any.String().Alpha().WithLengthBetween(1, 50).Generate();

        Order order = new Order(anyReference, anyCustomer, amount: 100m);

        // Act
        order.ApplyDiscount(20);

        // Assert
        Assert.Equal(80m, order.Total);
    }

}

The attribute applies at three levels, and the most specific one wins for the duration of a test:

// On a class: every test it declares is reproducible.
[Reproducible]
public sealed class OrderTests {

    [Fact]
    public void A_20_percent_discount_takes_a_fifth_off_the_order() {
        // Arrange
        string anyReference = Any.String().StartingWith("ORD-").WithLength(12).Generate();
        string anyCustomer  = Any.String().Alpha().WithLengthBetween(1, 50).Generate();

        Order order = new Order(anyReference, anyCustomer, amount: 100m);

        // Act
        order.ApplyDiscount(20);

        // Assert
        Assert.Equal(80m, order.Total);
    }

    // On a method, replaying a reported seed — the outer level is restored afterwards.
    [Fact, Reproducible(Seed = 1743029518)]
    public void A_100_percent_discount_clears_the_order() {
        // Arrange
        string anyReference = Any.String().StartingWith("ORD-").WithLength(12).Generate();
        string anyCustomer  = Any.String().Alpha().WithLengthBetween(1, 50).Generate();

        Order order = new Order(anyReference, anyCustomer, amount: 100m);

        // Act
        order.ApplyDiscount(100);

        // Assert
        Assert.Equal(0m, order.Total);
    }

}

It also applies to a whole assembly, which is the form to reach for when reproducibility should be the default for a suite. Put this at the top of any file in the test project, before any namespace or type declaration:

[assembly: Reproducible]

What it does, precisely

Before each test case, the attribute opens the same ambient seed scope Any.Reproducibly uses, pinning a fresh seed — or the one you set on Seed. After the test, it closes the scope and, only if the test failed, writes the seed to the test’s output:

[JustDummies] These arbitrary values were seeded with 1743029518. Reproduce this run with [Reproducible(Seed = 1743029518)].

Notice that the message names the attribute, not Any.Reproducibly(seed, ...). A test pinned from outside its own body contains no such call, so naming it would send the reader looking for code that is not there. The adapter supplies its own replay snippet through the second Any.UseSeed overload — the reason that overload exists (ADR-0017 opens in a new tab).

Three consequences worth knowing:

  • One seed per test case, so each case of a [Theory] gets its own rather than sharing one.
  • A green test stays silent. The seed is a diagnostic aid, not output.
  • Any.WithSeed(...) contexts are unaffected. That context is isolated by design and does not draw from the ambient source this attribute pins.

Replaying a failure

Copy the seed from the failing test’s output onto the attribute, run it, and the exact values come back. Fix the defect, then remove the pin — a committed seed turns a varying test back into a one-case test.

Things the analyzers will tell you

RuleSituation
JD010[Reproducible] on a method xUnit does not treat as a test — it pins nothing and looks exactly like the working form
JD007a value drawn in a [Reproducible] class’s constructor, which xUnit runs before the scope opens, so the reported seed does not replay it
JD008a theory’s data provider drawing at discovery, before any seed is pinned

If you use xUnit v2

This adapter targets v3 only. On v2, use Any.Reproducibly(() => { ... }) inside the test body — it gives you the same pinned scope and the same seed report, at the cost of one wrapping lambda. See Reproducibility.

Read the source, or correct it there opens in a new tab· Mirrored from xunit-v1.0.0-preview.2