Skip to main content

C# Test Data Generator: Bogus Faker With StrictMode and xUnit

Bogus 35.6.5 generates realistic strings for .NET fixtures, and its `Faker<T>` rule chain is different from every other library in this cluster in one specific way: `StrictMode(true)` throws if you forget to configure a property. This guide shows how to build a deterministic rule chain and why adding a new rule in the middle reshuffles every downstream value.

Libraries confirmed

Bogus 35.6.5 (NuGet, retrieval note 2025-10-25) with xUnit `[Fact]`. Pin API names to the Bogus docs and Context7 mirror retrieved 2026-08-01, not marketplace blurbs.

Bogus StrictMode, AssertConfigurationIsValid, and add-rules-last determinism

Call StrictMode(true) before any RuleFor. A forgotten property then throws a ValidationException at generate time. Validate() returns a bool for unit assertions; AssertConfigurationIsValid() throws on the same gaps when you want an exception rather than a bool. Use Ignore for intentionally unconfigured properties (Bogus docs, retrieved 2026-08-01).

Add new RuleFor rules last. Inserting a rule mid-chain reshuffles the internal random stream for every property that follows, so the same UseSeed produces a different CustomerName sequence. The sample below asserts that before/after difference.

Runnable code sample

Verified against Bogus 35.6.5 docs retrieved 2026-08-01. Copy into your test tree and adjust domain vocabulary as needed.

// NuGet: Bogus 35.6.5 (nuget.org, retrieved 2025-10-25); xUnit [Fact]
using System.Collections.Generic;
using Bogus;
using Xunit;

public enum Channel { Web, Ios, PartnerApi }

public class Subscription
{
    public int Id { get; set; }
    public string CustomerName { get; set; }
    public Channel Channel { get; set; }
    public int MonthlySeats { get; set; }
}

public class SubscriptionFakerTests
{
    // StrictMode(true) before any RuleFor: unfinished rules fail loudly.
    private static Faker<Subscription> Builder() =>
        new Faker<Subscription>()
            .StrictMode(true)
            .RuleFor(s => s.Id, f => f.IndexFaker)
            .RuleFor(s => s.CustomerName, f => f.Name.LastName())
            .RuleFor(s => s.Channel, f => f.PickRandom<Channel>())
            .RuleFor(s => s.MonthlySeats, f => f.Random.Number(1, 250));

    [Fact]
    public void SameLocalSeedProducesTheSameSubscriptions()
    {
        List<Subscription> first = Builder().UseSeed(4242).Generate(20);
        List<Subscription> second = Builder().UseSeed(4242).Generate(20);

        Assert.Equal(
            first.ConvertAll(s => s.CustomerName),
            second.ConvertAll(s => s.CustomerName));
    }

    [Fact]
    public void EveryPropertyHasARule()
    {
        // Validate() returns bool; AssertConfigurationIsValid() throws on gaps.
        Assert.True(Builder().Validate());
        Builder().AssertConfigurationIsValid();
    }

    [Fact]
    public void InsertingARuleMidChainReshufflesDownstreamValues()
    {
        var threeRules = new Faker<Subscription>()
            .StrictMode(true)
            .RuleFor(s => s.Id, f => f.IndexFaker)
            .RuleFor(s => s.CustomerName, f => f.Name.LastName())
            .RuleFor(s => s.Channel, f => f.PickRandom<Channel>())
            .RuleFor(s => s.MonthlySeats, f => f.Random.Number(1, 250))
            .UseSeed(4242)
            .Generate(5);

        // New RuleFor inserted before CustomerName: same seed, different names.
        var fourRulesInserted = new Faker<Subscription>()
            .StrictMode(true)
            .RuleFor(s => s.Id, f => f.IndexFaker)
            .RuleFor(s => s.MonthlySeats, f => f.Random.Number(1, 250)) // inserted mid-chain
            .RuleFor(s => s.CustomerName, f => f.Name.LastName())
            .RuleFor(s => s.Channel, f => f.PickRandom<Channel>())
            .UseSeed(4242)
            .Generate(5);

        Assert.NotEqual(
            threeRules.ConvertAll(s => s.CustomerName),
            fourRulesInserted.ConvertAll(s => s.CustomerName));
    }
}

When to use Generate-Data instead

Use Bogus in-process when fixtures must live next to xUnit assertions in CI. Use the free generator when you need a downloadable file (csv, json, xml, parquet, xlsx, jsonl, hf-datasets when signed in), labeled duplicates with Master ID / Duplicate Type, or exports beyond what your library emits. Anonymous use is capped at 100 rows, 6 fields, 3 exports, and CSV only. See the generator comparison and export formats guide.

Frequently asked questions

Bogus or AutoFixture, and can I use both?

They suit different workflows and can be combined. A DEV Community post (https://dev.to/nausaf/why-i-moved-from-autofixture-to-bogus-for-test-data-generation-for-cxunit-test-49kg, observed 2026-08-01) moved off AutoFixture because "there seems to be no out of the box way of generating a number in a specified range." The AutoFixture repository (https://github.com/AutoFixture/AutoFixture, observed 2026-08-01) shows the feature the same post does not weigh: `[Theory, AutoData]` injects fixture values directly as xUnit theory parameters, which Bogus's rule-chain design has no equivalent of. The `AutoBogus` NuGet package (in the Bogus dependents table, observed 2026-08-01) bridges the two by driving AutoFixture population from Bogus rules. The honest answer: use Bogus where you want named realistic vocabulary and rule completeness enforcement; use AutoFixture's `[AutoData]` where you want declarative parameter injection; use AutoBogus if you want both.

How do I get the same fake data on every test run?

Use `Faker<T>.UseSeed(int)` rather than the global `Randomizer.Seed`. The Bogus docs give two reasons: the global setter affects every faker instance in the process, and its effects are order-dependent on when tests run. Prefer local: call `.UseSeed(4242)` on the specific `Faker<T>` builder you want to be deterministic. For methods that involve dates, also call `.UseDateTimeReference(...)` to pin the reference date, because date methods are relative to today by default. Both confirmed from the Bogus docs via https://github.com/bchavez/Bogus and the Context7 mirror (https://context7.com/bchavez/bogus/llms.txt), retrieved 2026-08-01.

How do I catch a property I forgot to configure?

Call `.StrictMode(true)` before any `.RuleFor` calls. If you call `.Generate()` with a property that has no rule, Bogus throws a `ValidationException` listing the missing property names. For a bool check in a unit test rather than an exception, use `.Validate()` which returns `true` when every property has a rule. Use `.AssertConfigurationIsValid()` when you want the same check to throw. Use `.Ignore(x => x.ComputedProp)` to tell Bogus a property is intentionally unconfigured. `StrictMode`, `Validate`, `AssertConfigurationIsValid`, and `Ignore` were all confirmed from the same Bogus docs, retrieved 2026-08-01.

More C# testing guides