JustDummies

Just dummies — but seriously powerful ones.

Why JustDummies

JustDummies generates the arbitrary values a test needs, and lets you state the rules those values have to satisfy.

Not every value in a test carries the scenario. The ones that do not still have to respect the rules of the domain — that is the part JustDummies takes care of. See the full example, step by step.

Which of these do you need?

These four are usually listed as rivals. They answer four different questions, and most projects ask more than one of them. Find the sentence you would say out loud.

JustDummies

I do not care what this value is, but it has to be valid.

Arbitrary values for everything a test does not check, with the rules they must satisfy written where the value is asked for.

In practice: a reference that always starts with ORD-, is uppercase alphanumeric after that prefix, and is between eight and twenty characters long, drawn fresh on every run.

View the repository opens in a new tab

Bogus

I need data that looks real.

A simple fake data generator for C#, F#, and VB.NET — ported from the well-known faker.js.

In practice: names, addresses, emails, phone numbers, product labels — locale-aware, and convincing to a person reading a screenshot or a demo database.

View the repository opens in a new tab

AutoFixture

Just build me the object. I do not care what is in it.

A library that removes the need to hand-code anonymous variables when setting up a test's fixture.

In practice: one call returns a fully populated object, everything it holds filled in too, including types you did not write — with nothing declared anywhere.

View the repository opens in a new tab

Hardcoded value

This exact value is what the test checks.

No library at all: the value typed straight into the test, on the line that uses it.

In practice: the amount an assertion compares against, or the status a behaviour turns on. A reader sees it without leaving the test.

JustDummies vs. the alternatives

Ten criteria, each one a question about your own tests, answered for all four options.

What each answer means
Built for this
The tool is built for this, and does it with no extra setup.
Possible, with work
The tool can get there, but you write something to get there. The note says what.
Not what it does
The tool does not do this. Sometimes its authors decided against it, sometimes nobody has built it yet — the note says which.

The full comparison table

Every answer at a glance, without the notes behind them. Each criterion links down to the block that explains it.

  • Built for this
  • Possible, with work
  • Not what it does
Four ways to get a test value, criterion by criterion.
CriterionJustDummiesBogusAutoFixtureHardcoded value
Will the value get through my own code?
Values your own code will acceptBuilt for thisPossible, with workPossible, with workPossible, with work
Rules stated where the value is asked forBuilt for thisPossible, with workPossible, with workNot what it does
Filling nested objects for youPossible, with workPossible, with workBuilt for thisPossible, with work
Will my test still be readable?
Showing which value the test checksBuilt for thisPossible, with workBuilt for thisPossible, with work
Describing a valid object oncePossible, with workPossible, with workPossible, with workPossible, with work
What kind of value do I actually need?
Data that looks realNot what it doesBuilt for thisNot what it doesPossible, with work
Hunting for the value that breaks your codeNot what it doesNot what it doesNot what it doesNot what it does
What happens when it goes wrong, and who writes the setup?
Replaying the run that failedBuilt for thisBuilt for thisNot what it doesBuilt for this
Caught before the test runsBuilt for thisPossible, with workNot what it doesNot what it does
A tool writing the setup for youBuilt for thisPossible, with workNot what it doesNot what it does

The criteria are grouped by the questions you might ask in your own tests, not by what JustDummies is good at. And JustDummies deliberately does not try to cover every need: its goal is to do one thing well, generating the arbitrary and constrained values your tests need.

Will the value get through my own code?

Values your own code will accept

Will the generated value get past my own constructor?

Most domain types refuse bad input. OrderReference.Create rejects a string that does not start with ORD-, one shorter than eight characters or longer than twenty, and one carrying anything but an uppercase letter or a digit after the prefix. A test that needs any reference still needs one that clears every check.

Technical term: business invariant, or precondition in design by contract

string reference = Any.String()
                      .AlphaNumeric()
                      .InUpperCase()
                      .StartingWith("ORD-")
                      .WithLengthBetween(8, 20)
                      .Generate();
produced, run after runORD-KOKR06JCSSORD-BHW5BL44FJC1VORD-WZYMJV2FMORD-A243EM1HKJJEEB3
  • JustDummiesBuilt for this
  • BogusPossible, with work

    A Faker<T> satisfies a domain rule once a RuleFor is written to match it — or a CustomInstantiator that calls the type's own factory. StrictMode(true) then checks that every property has a rule at all. What no check covers is whether a rule produces a value the domain would accept.

  • AutoFixturePossible, with work

    A rule a type carries as an annotation — [Range], [StringLength], [RegularExpression] — is already honoured, with no configuration at all. A rule enforced inside a constructor is the other case: generation throws until a Register, a Customize<T> or an ISpecimenBuilder is written to satisfy it.

  • Hardcoded valuePossible, with work

    Valid because a person chose a value they knew was valid. Nothing checks that it still is the day the rule changes.

Rules stated where the value is asked for

Can I write "any number between 1 and 100" on the line that needs it?

Some rules belong to one test rather than to the domain: this quantity has to be at least two, this date has to be in the past. The question is whether you can say so on the spot, or have to declare a type, register a customisation or build a fixture first.

Technical term: call site — the place in your code where the value is asked for

int quantity = Any.Int32().Between(1, 100).Generate();
produced, run after run91596442
  • JustDummiesBuilt for this
  • BogusPossible, with work

    A Faker<T> can be built inline in the test, right before Generate, with its rules on it — Random.Int(min, max) and the like. You write those rules out again in every test that needs them.

  • AutoFixturePossible, with work

    A rule that lives on the type is honoured everywhere without a line in the test. A rule that belongs to this one test is written inline through Build<T>().With(x => x.Prop, value) — a pinned value, or a lambda you write, one property at a time.

  • Hardcoded valueNot what it does

    The rule is never stated. You pick a value that happens to satisfy it, and the rule stays in the head of whoever picked it.

Filling nested objects for you

My type is three levels deep and the test cares about none of it — who fills it?

An order holds a customer, which holds an address. Either something inspects your class and populates every level, or you supply one generator per type and plug them together.

Technical term: object graph

  • JustDummiesPossible, with work

    You supply one generator per type and compose them. Nothing inspects your class and fills the levels underneath.

  • BogusPossible, with work

    A nested object is built by hand inside the rule that produces it. Bogus does not descend into it for you.

  • AutoFixtureBuilt for this
  • Hardcoded valuePossible, with work

    Every nested object is constructed by hand, level by level, and each constructor is a line you write and then maintain.

Will my test still be readable?

Showing which value the test checks

Can a reader tell which values the assertion depends on?

A test that builds an order from four arguments does not say which of the four it is about. Drawing three of them and writing the fourth as a literal answers that in the arrangement itself.

  • JustDummiesBuilt for this
  • BogusPossible, with work

    RuleFor(x => x.Prop, expected) pins the exact value the assertion checks, so the subject of the test is written down. The rules around it are written down just as visibly.

  • AutoFixtureBuilt for this

    This is the goal AutoFixture states for itself: the values a test does not care about disappear, because you never describe them. What disappears with them is any statement of what those values must satisfy.

  • Hardcoded valuePossible, with work

    It shows the value the test is about with no indirection at all. Used for the parameters around it as well, the arrangement grows a line per parameter and the subject stops standing out.

Describing a valid object once

The day my type gains a constructor parameter, how many test files do I reopen?

Whatever describes a valid order — a chain of constraints, a set of rules, a builder — is worth writing once and calling from everywhere. The question is what that costs to set up, and how much of it the tool writes for you.

  • JustDummiesPossible, with work

    Write the generator once, in your own test project, and every test can call it. The dum tool — the library's own companion CLI — can write that file for you. Neither happens from a single call.

  • BogusPossible, with work

    A Faker<T> is defined once and reused across tests, the same way a JustDummies generator is.

  • AutoFixturePossible, with work

    An ICustomization packages a set of rules once, in a class of its own, and every test that opts into it gets them.

  • Hardcoded valuePossible, with work

    A literal can move into a named constant or a helper and be shared. You then maintain it by hand, and every test that shares it runs on the same value.

What kind of value do I actually need?

Data that looks real

Will a person look at this value, or only an assertion?

Valid and believable are two different jobs. A reference that clears every rule can still read as machine noise. That is fine in an assertion and wrong in a screenshot.

Technical term: fake data — the faker family of libraries

  • JustDummiesNot what it does

    Valid, not believable. There is no catalogue of names, addresses or emails here.

  • BogusBuilt for this
  • AutoFixtureNot what it does

    The values are anonymous by design — a string comes out as a property name and a GUID. Looking real is not what AutoFixture is trying to do.

  • Hardcoded valuePossible, with work

    As realistic as the value you type: marie.durand@acme.fr is every bit as convincing as a generated one. You type it again in the next test.

Hunting for the value that breaks your code

Do I want one arbitrary value, or hundreds looking for a counter-example?

One drawn value per run tells you the code held for that value. The opposite approach runs the same assertion over hundreds of generated inputs, then narrows any failure down to the smallest input that still fails.

Technical term: property-based testing, and shrinking

  • JustDummiesNot what it does

    One value is drawn per run, and you can draw it again. There is no systematic search for the input that fails.

  • BogusNot what it does

    Bogus fills values. It does not run your test repeatedly looking for one that fails.

  • AutoFixtureNot what it does

    One anonymous value per request, not a search for the one that makes your code fail.

  • Hardcoded valueNot what it does

    One value, chosen once, and the same one for the life of the test.

None of the four does this. In .NET the usual answers are FsCheck and CsCheck, and they sit beside any of these rather than replacing one.

What happens when it goes wrong, and who writes the setup?

Replaying the run that failed

CI went red on a drawn value. Can I get that exact value back?

Values that change on every run mean a test can fail today and pass tomorrow. What makes that workable is a number the failing run reports, which draws the same values again when you paste it back.

Technical term: seed

  • JustDummiesBuilt for this

    A failing test case reports its seed, and that seed redraws exactly the same values. Each case seeds itself, so a suite running in parallel still hands back the seed of the one that failed. This comes from the xUnit adapter; there is no NUnit or MSTest adapter today.

  • BogusBuilt for this

    UseSeed on a Faker, or Randomizer.Seed for the whole run, makes a run repeatable.

  • AutoFixtureNot what it does

    There is no seed to set, so a run cannot be replayed value for value. That is a gap rather than a decision: repeatable random numbers are an open request on the project, filed in September 2023.

  • Hardcoded valueBuilt for this

    The same value on every run, because it is the value you typed. Nothing to replay, and nothing that varies.

Caught before the test runs

Do I learn the setup is wrong in the editor, or ten minutes later?

A chain of constraints can contradict itself: at most three characters, and starting with ORD-. Nothing satisfies that. The question is whether it shows up as a build error or as an exception on the first run.

Technical term: Roslyn analyzer

  • JustDummiesBuilt for this

    The analyzers ship inside the main package at no extra cost — installing the library installs them, with no paid tier standing between you and them. They catch a self-contradictory constraint immediately, in the editor: at most three characters, say, and starting with ORD-. What stays out of reach here is a domain invariant nobody declared as a rule at all — enforced in ordinary constructor code, with no structured list of a type's own invariants for an analyzer to check completeness against. That is narrower than it sounds: Bogus Premium's analyzer can flag a property with no RuleFor, because a Faker<T>'s properties are a known, enumerable set. A hand-written constructor's own invariants are not.

  • BogusPossible, with work

    The free package catches a missing rule when the test runs: StrictMode(true) makes Generate throw, and AssertConfigurationIsValid checks on demand. Catching it while you type is the Bogus Premium analyzer, which is a paid licence.

  • AutoFixtureNot what it does

    No analyzer ships with it. A customization that can never produce a value is found when the test runs.

  • Hardcoded valueNot what it does

    The compiler accepts any value of the right type — an overlong string, say. Only the domain constructor catches it, at run time.

A tool writing the setup for you

Do I hand-write a builder for each of my forty domain types?

The constraints for an order are a file somebody has to write, and rewrite the day the type gains a parameter. The question is whether a tool reads your own source and writes it. What it writes is ordinary C# in your test project: read it, edit it, commit it.

Technical term: scaffolding — not a source generator, which runs at build time and leaves you no file

  • JustDummiesBuilt for this

    The dum tool reads your type and writes the generator into your test project. The file is ordinary C#, and it is yours to edit and commit.

  • BogusPossible, with work

    The same Premium analyzer offers the missing rule as a one-click fix in the editor. That is help of a different shape from a file a tool writes and you keep.

  • AutoFixtureNot what it does

    Nothing writes a file for you, and the point is the opposite: with no rules to declare, there is no setup code to write.

  • Hardcoded valueNot what it does

    You type it. There is nothing to generate.

When another tool is the better answer

Three cases where one of the others is the right choice.

Bogus

Choose Bogus when the data has to look real: names, addresses, emails, a demo database somebody will read. Its catalogue is locale-aware, which is work you would otherwise do by hand. JustDummies draws valid values, not believable ones.

AutoFixture

Choose AutoFixture when the test needs a whole object and has nothing to say about what is in it. One call fills the object and everything it holds, including types you did not write. JustDummies starts from the rules; where there are no rules to state, it adds a step and buys nothing.

Hardcoded value

Write the literal for the value the test is about — the amount an assertion compares against, the status a behaviour turns on. A reader sees the exact value on the line that uses it. A drawn value there would only ask them to take it on trust.

When not to use JustDummies

Cases where another tool, or no tool at all, is the better answer.

  • The data has to look real.

    A demo, a screenshot, a database somebody will browse. Reach for a fake-data generator. A valid value is not a believable one.

  • You want the test to go looking for a counter-example.

    Running one assertion over hundreds of generated inputs, then shrinking a failure to its smallest case, is property-based testing. JustDummies draws one value per run, and it is not that tool.

  • You need a password, a token or a key.

    The generators produce test values, not secrets. Nothing drawn here is fit to be used as a credential, in a test or anywhere else.

Try it

Add the package to a test project and change one line of one arrangement. Every other test stays as it is. Bogus, AutoFixture, your own builders and every literal you have already written keep working, in the same project and in the same file. If it does not earn its place, backing it out is deleting the lines you added.

Install the library

dotnet add package JustDummies --prerelease

How this comparison was checked

Every claim about another project on this page comes from that project's own documentation or repository. What was read, and where, is below.

Last checked on August 16, 2026

Bogus

Read: the locale-aware catalogue (Name, Address, Internet, Commerce), RuleFor and the rules that can be chained on a Faker<T> built inline, the bounded draws such as Random.Int(min, max), StrictMode and AssertConfigurationIsValid, UseSeed and Randomizer.Seed, and the paid Bogus Premium tier whose analyzer flags a missing RuleFor and can insert it.

AutoFixture

Read: anonymous rather than realistic values, automatic construction of values of virtually any type, the [Range], [StringLength] and [RegularExpression] annotations honoured with no configuration, the Build<T>().With(...) override, the separate ISpecimenBuilder and Customize<T>() path, and the still-open request for repeatable random values.

Named but not compared

The two property-based testing libraries this page points to, for the one criterion none of the four options answers. Both were read to confirm they do what the page says.

If you maintain one of these projects and this page gets it wrong, an issue is the fastest way to have it corrected. Open an issue opens in a new tab