Updated on

Bogus is a .NET library that generates realistic fake data, such as names, emails, addresses and whole object graphs, from rules we write once per class.

We’ll use it to fill C# objects, make the output repeatable for tests, and save it to an EF Core database. Then we’ll look at the community extensions, including where AutoBogus stands today.

To download the source code for this article, you can visit our GitHub repository.

Let’s get going.

What Is Bogus in .NET?

Bogus is a fake data generator for .NET. We describe a class once with rules, and Bogus fills as many instances as we ask for with realistic names, emails, addresses, numbers and dates.

Its author describes it as “fundamentally a C# port of faker.js”, the fake data library from the JavaScript world. The syntax is inspired by FluentValidation, so a rule reads like RuleFor(e => e.Email, f => f.Internet.Email()).

The values can also depend on each other. A rule can read the values that earlier rules produced, so an email can be built from the first and last name of the same person.

Bogus works from C#, F# and VB.NET, and the package has more than 280 million downloads on NuGet.

We reach for it in three places: test data for unit and integration tests, demo data for a UI, and development data in a database. The Faker<T> class is the entry point, and everything in this article builds on it.

If we’ve used faker.js before, or followed our FluentValidation article, most of Bogus will look familiar.

Why Use Bogus?

What are the benefits of using Bogus? There are lots of them, but the most important one is that we can save ourselves a lot of time that we would spend by creating fake data manually. With Bogus, we can specify our classes and their relations, and configure Bogus rules to generate fake data.

That said, we can use built-in generators from Bogus to create different data like addresses, phone numbers, emails, etc. On top of that, we can realistically connect our data. For example, if we have an Employee class that has FirstName and LastName properties, we can use those properties to generate Email for that object. That way, our data will look better when we display it.

Bogus has a wide spectrum of usages. We can use it for mocking our test data, seeding fake data to our databases, and even integrating it with Entity Framework Core, which we will see in this article.

Preparing the Environment

Let’s get our hands dirty.

First, we will start by preparing the environment and creating classes that we will use to generate fake data with Bogus.

Let’s start with the Employee class:

using System.Text.Json;

public sealed class Employee 
{
    public Guid Id { get; set; }
    public string FirstName { get; set; } = default!;
    public string LastName { get; set; } = default!;
    public string Address { get; set; } = default!;
    public string Email { get; set; } = default!;
    public string AboutMe { get; set; } = default!;
    public int YearsOld { get; set; }
    public Personality Personality { get; set; }
    public List<Vehicle> Vehicles { get; set; } = default!;

    public override string ToString()
    {
        return JsonSerializer.Serialize(this, new JsonSerializerOptions { WriteIndented = true });
    }
}

Here, we add the Employee class with some usual properties like Id, FirstName, LastName, Address, etc. However, we also have the Personality enum:

public enum Personality
{
    Positive,
    Negative,
    Neutral
}

And the list of Vehicle objects per each employee:

using System.Text.Json;

public sealed class Vehicle
{
    public Guid Id { get; set; }
    public Guid EmployeeId { get; set; }
    public string Manufacturer { get; set; } = default!;
    public string Fuel { get; set; } = default!;

    public override string ToString()
    {
        return JsonSerializer.Serialize(this, new JsonSerializerOptions { WriteIndented = true });
    }
}

In both Employee and Vehicle classes, we override the ToString() method to serialize and indent our data, to display it nicely later in the article.

We now have our employees with vehicles, but we only have classes. What about the specific objects?

That’s where Bogus comes in.

Bogus Configuration in .NET

To start using Bogus, we need to configure it first. Initially, we will install Bogus with .NET CLI. Then, we will specify Bogus rules and relations between the classes we created in the previous section.

Bogus Installation in .NET

First, let’s install the Bogus NuGet package through .NET CLI:

dotnet package add Bogus

Great, now we have Bogus included in our .NET project, and it is ready to use.

Specifying Bogus Rules

Now, it’s time to specify Bogus rules that we want to enforce for our classes and objects that we will generate. We will put our data-related code to the DataGenerator class, in a file that starts with using Bogus;.

First, let’s start with the data generator for the Vehicle class:

private static Faker<Vehicle> GetVehicleGenerator(Guid employeeId)
{
    return new Faker<Vehicle>()
        .RuleFor(v => v.Id, _ => Guid.NewGuid())
        .RuleFor(v => v.EmployeeId, _ => employeeId)
        .RuleFor(v => v.Manufacturer, f => f.Vehicle.Manufacturer())
        .RuleFor(v => v.Fuel, f => f.Vehicle.Fuel());
}

In the GetVehicleGenerator() method, we create a new Faker object from Bogus, which accepts, as its generic type argument, the class for which we are specifying the rules, in this case, the Vehicle class. We specify a different rule for each property of the Vehicle class, with the RuleFor() method.

Of course, a different property has different rules in this case:

  • The Id property gets value in form of the new Guid, which is different for each object
  • The EmployeeId property is set through the employeeId input parameter
  • The Manufacturer property uses the Vehicle dataset from the Faker class, and picks a random manufacturer for each object
  • Similarly, the Fuel property gets the value with the Fuel() method from the Bogus Vehicle dataset

Similarly, let’s specify rules for the Employee class:

private static Faker<Employee> GetEmployeeGenerator()
{
    return new Faker<Employee>()
        .RuleFor(e => e.Id, _ => Guid.NewGuid())
        .RuleFor(e => e.FirstName, f => f.Name.FirstName())
        .RuleFor(e => e.LastName, f => f.Name.LastName())
        .RuleFor(e => e.Address, f => f.Address.FullAddress())
        .RuleFor(e => e.Email, (f, e) => f.Internet.Email(e.FirstName, e.LastName))
        .RuleFor(e => e.AboutMe, f => f.Lorem.Paragraph(1))
        .RuleFor(e => e.YearsOld, f => f.Random.Int(18, 90))
        .RuleFor(e => e.Personality, f => f.PickRandom<Personality>())
        .RuleFor(e => e.Vehicles, (_, e) =>
        {
            return GetBogusVehicleData(e.Id);
        });
}

Again, in the GetEmployeeGenerator() method, we create a new Faker object which we will use later for creating fake employees. We can see a couple of different Bogus datasets being used in this example, like Name, Address, Internet and Lorem. Have a look at how we use our FirstName and LastName generated values as input parameters when creating an email address with the Email() function from the Internet dataset. In this way, we ensure our data is realistic.

Also, we use the Int() method from the Randomizer object to populate the YearsOld value within a specific range. Similarly, the PickRandom() method is used to seed Personality values from our Personality enumeration.

We use our GetBogusVehicleData() method, which we will inspect later, to create nested Vehicle objects and populate the value of the Vehicles property for each different Employee.

In our case, we only use a couple of datasets that Bogus is offering, however, there are many more, like Commerce, Company, Finance, Images, System, etc.

Generating Data With Bogus

Our data generators are ready and we can start generating our fake data inside the DataGenerator class.

First, let’s specify some class members for storing our generated data:

public static readonly List<Employee> Employees = [];
public static readonly List<Vehicle> Vehicles = [];

Here, we define two static read-only List objects, Employees and Vehicles, which we will use to store our generated data.

Next, let’s create some constants for defining how much data we want to generate:

public const int NumberOfEmployees = 5;
public const int NumberOfVehiclesPerEmployee = 2;

Here we define how many employee records we want to generate with Bogus, and how many vehicles will each employee have.

Finally, let’s add initialization methods for generating data and storing it in our Employees and Vehicles variables:

private static List<Vehicle> GetBogusVehicleData(Guid employeeId)
{
    var vehicleGenerator = GetVehicleGenerator(employeeId);
    var generatedVehicles = vehicleGenerator.Generate(NumberOfVehiclesPerEmployee);
    Vehicles.AddRange(generatedVehicles);
    return generatedVehicles;
}

This is the GetBogusVehicleData() method that we used before when creating a data generator for employees. Here, we retrieve the Faker object for vehicle generation and store it in the vehicleGenerator variable. Then, we use the vehicleGenerator to generate a number of vehicles specified by the NumberOfVehiclesPerEmployee value, initialized on the class level. Before returning the generated data, we first add our generatedVehicles to the Vehicles list from our class.

The only piece that is missing is the employee initialization method:

public static void InitBogusData()
{
    var employeeGenerator = GetEmployeeGenerator();
    var generatedEmployees = employeeGenerator.Generate(NumberOfEmployees);
    Employees.AddRange(generatedEmployees);
}

Here, in a similar fashion, we fetch our employee generator and generate a specific number of employees determined by the NumberOfEmployees value. After storing the data in the generatedEmployees variable, we also add our data to the Employees list.

To prepare and initialize our static DataGenerator class, let’s call the InitBogusData() from the Program class:

Console.WriteLine("Initializing data with Bogus...");
DataGenerator.InitBogusData();

Perfect, we are ready to see what our data looks like.

Generating a Fake Record

We have our generated data initialized in our Employees and Vehicles fields. Let’s see our first employee and display it through the Program class:

Console.WriteLine("Single Employee: ");
Console.WriteLine(DataGenerator.Employees.First());

And check the results:

Single Employee:
{
  "Id": "fb121674-7aec-4415-b5f4-5f91749b0ec3",
  "FirstName": "Nelda",
  "LastName": "Baumbach",
  "Address": "790 Josianne Trafficway, Thielville, Saudi Arabia",
  "Email": "[email protected]",
  "AboutMe": "Consectetur officiis doloribus distinctio. Omnis eveniet ut perferendis ullam nobis.",
  "YearsOld": 85,
  "Personality": 2,
  "Vehicles": [
    {
      "Id": "ea48314b-a825-448b-8057-bed11da24d8c",
      "EmployeeId": "fb121674-7aec-4415-b5f4-5f91749b0ec3",
      "Manufacturer": "Nissan",
      "Fuel": "Gasoline"
    },
    {
      "Id": "edc3276d-be13-49a6-a675-9cc63208d0ad",
      "EmployeeId": "fb121674-7aec-4415-b5f4-5f91749b0ec3",
      "Manufacturer": "Nissan",
      "Fuel": "Electric"
    }
  ]
}

We can see the Employee object has been generated with two vehicles. Pay attention to the correlation between the FirstName, LastName and the Email values, it all makes sense. Apparently, our first employee is a fan of Nissan.

Bogus always starts these emails with the first name (D’angelo becomes Dangelo), but it picks one of three formats, and only two of them include the last name. Our second employee below, Carrie Blanda, gets [email protected]. When we generated 100,000 employees with this rule, 33% of the emails had no last name in them, so a test should never assume one.

Generating Multiple Fake Records

Our first employee looks great, but we should also check for multiple employees. For that, let’s display them as well:

Console.WriteLine("Multiple Employees: ");
DataGenerator.Employees.ForEach(Console.WriteLine);

And see what our console looks like:

Multiple Employees:
{
  "Id": "fb121674-7aec-4415-b5f4-5f91749b0ec3",
  "FirstName": "Nelda",
  "LastName": "Baumbach",
  "Address": "790 Josianne Trafficway, Thielville, Saudi Arabia",
  "Email": "[email protected]",
  "AboutMe": "Consectetur officiis doloribus distinctio. Omnis eveniet ut perferendis ullam nobis.",
  "YearsOld": 85,
  "Personality": 2,
  "Vehicles": [
    {
      "Id": "ea48314b-a825-448b-8057-bed11da24d8c",
      "EmployeeId": "fb121674-7aec-4415-b5f4-5f91749b0ec3",
      "Manufacturer": "Nissan",
      "Fuel": "Gasoline"
    },
    {
      "Id": "edc3276d-be13-49a6-a675-9cc63208d0ad",
      "EmployeeId": "fb121674-7aec-4415-b5f4-5f91749b0ec3",
      "Manufacturer": "Nissan",
      "Fuel": "Electric"
    }
  ]
}
{
  "Id": "df36ce57-7fcd-45ee-ac93-c471a0aa071f",
  "FirstName": "Carrie",
  "LastName": "Blanda",
  "Address": "32951 Dustin Neck, New Paula, Kyrgyz Republic",
  "Email": "[email protected]",
  "AboutMe": "Quo non saepe impedit nobis velit et. Ipsam consequatur aspernatur voluptatem.",
  "YearsOld": 58,
  "Personality": 1,
  "Vehicles": [
    {
      "Id": "dd1a484b-48a9-48ef-88e5-cbbd79f40943",
      "EmployeeId": "df36ce57-7fcd-45ee-ac93-c471a0aa071f",
      "Manufacturer": "Land Rover",
      "Fuel": "Hybrid"
    },
    {
      "Id": "6b6de641-8560-4ea5-afd4-88658ffcbad5",
      "EmployeeId": "df36ce57-7fcd-45ee-ac93-c471a0aa071f",
      "Manufacturer": "Honda",
      "Fuel": "Gasoline"
    }
  ]
}

For the sake of simplicity, we only show our first two employees from the console output. That’s enough for us to confirm that the data looks good.

Generating the Same Data on Every Run

Every run so far gives us different employees. That’s what we want for demo data, but a failing test is much easier to fix when it fails with the same data twice.

Bogus handles this with a seed. Let’s add a method to the DataGenerator class that generates vehicles from a seed we pass in:

public static List<Vehicle> GenerateRepeatableVehicles(int seed)
{
    return new Faker<Vehicle>()
        .UseSeed(seed)
        .RuleFor(v => v.Id, f => f.Random.Guid())
        .RuleFor(v => v.Manufacturer, f => f.Vehicle.Manufacturer())
        .RuleFor(v => v.Fuel, f => f.Vehicle.Fuel())
        .Generate(NumberOfVehiclesPerEmployee);
}

The UseSeed() method gives this Faker its own random sequence, so the same seed produces the same vehicles in every run.

Have a look at the Id rule, too. Here, we use f.Random.Guid() instead of Guid.NewGuid(). Guid.NewGuid() knows nothing about our seed, so it would hand us new IDs on every run while the rest of the record stayed the same.

Let’s call the method with the seed 1338 and check the result:

{
  "Id": "db34c393-8027-7502-a9e4-e94a9b7fba23",
  "EmployeeId": "00000000-0000-0000-0000-000000000000",
  "Manufacturer": "Ferrari",
  "Fuel": "Gasoline"
}
{
  "Id": "75c1ab30-c1b8-1d1d-63c7-7d1e3fbbf816",
  "EmployeeId": "00000000-0000-0000-0000-000000000000",
  "Manufacturer": "Rolls Royce",
  "Fuel": "Gasoline"
}

We get exactly these two vehicles on every run, which makes seeded fakers a good fit for xUnit tests.

Bogus also has a global Randomizer.Seed field, but its documentation recommends UseSeed() for tests, because with a local seed a change to one Faker can’t shift the values another one produces. Mind you, seeded output can still change when we move to a new major version of Bogus, which the library treats as a breaking change.

Seeding an EF Core Database With Bogus

Until now, we were using Bogus to generate our data and display it in the console. However, in real-world scenarios, we would probably use a data generator like Bogus to seed our fake data to the database, for testing purposes.

Creating Context and Configuring EF Core

Entity Framework Core is the industry standard when working with .NET, as it supports a lot of database providers. Luckily, we can easily integrate Bogus with Entity Framework.

First, we need to install the Microsoft.EntityFrameworkCore.SqlServer and Microsoft.EntityFrameworkCore.Design packages, and you can find more about the process in our EF Core series. Once that is done, let’s create an EmployeeContext class that derives from DbContext, with DbSet<Employee> Employees and DbSet<Vehicle> Vehicles properties and using Microsoft.EntityFrameworkCore; at the top of its file. Then we register our seeding logic with the UseSeeding() method inside OnConfiguring():

protected override void OnConfiguring(DbContextOptionsBuilder options)
{
    options.UseSqlServer("Server=localhost;Database=EmployeeDb;Trusted_Connection=True;MultipleActiveResultSets=True;TrustServerCertificate=True")
        .UseSeeding((context, _) =>
        {
            if (context.Set<Employee>().Any())
            {
                return;
            }

            context.Set<Employee>().AddRange(DataGenerator.Employees);
            context.SaveChanges();
        });
}

EF Core runs the UseSeeding() delegate whenever it creates or migrates the database. Inside it, we check whether any employees exist, and if not, we add our generated employees and save them.

Because each Employee carries its own Vehicles, a single SaveChanges() call fills both tables.

Why not the HasData() method in OnModelCreating()? It looks like the natural place, but the EF Core documentation calls UseSeeding() “the recommended way of seeding the database with initial data” and keeps HasData() for static data that changes only through migrations. Our data is the opposite: random, and new on every run. On top of that, HasData() rejects our employees outright, because they carry their vehicles in a navigation property.

Then, we need to create an Entity Framework Core migration.

Fetching Data From EF Core Database

Now, let’s add a new method to the DataGenerator class, with using Microsoft.EntityFrameworkCore; at the top of its file, to execute the migration and fetch the seeded data from the database:

public static List<Employee> GetSeededEmployeesFromDb()
{
    using var employeeDbContext = new EmployeeContext();

    employeeDbContext.Database.Migrate();

    var dbEmployeesWithVehicles = employeeDbContext.Employees
           .Include(e => e.Vehicles)
           .ToList();

    return dbEmployeesWithVehicles;
}

In the GetSeededEmployeesFromDb() method, we initialize a new context and call the Migrate() method, to create our database and apply our migration if it is not applied yet. Right after that, EF Core runs our UseSeeding() logic, which adds the employees on the first run only. Then, we fetch the data from the Employees set and use the Include() method to include all employee vehicles through the foreign key. Lastly, we return the data.

To confirm that our functionality works, let’s display our employees from the database in the Program class:

Console.WriteLine("DB Seeded Employees: ");
DataGenerator.GetSeededEmployeesFromDb().ForEach(Console.WriteLine);

And check the console output:

DB Seeded Employees:
{
  "Id": "46544fa0-5c07-41b2-92bd-3a38d8c2f060",
  "FirstName": "Jackie",
  "LastName": "Gislason",
  "Address": "776 Maggio Camp, Port Britneyland, Argentina",
  "Email": "[email protected]",
  "AboutMe": "Quia voluptatem non aperiam et tenetur excepturi aut.",
  "YearsOld": 79,
  "Personality": 1,
  "Vehicles": [
    {
      "Id": "682a28ff-b923-4b28-9e8c-436de6896717",
      "EmployeeId": "46544fa0-5c07-41b2-92bd-3a38d8c2f060",
      "Manufacturer": "Bentley",
      "Fuel": "Gasoline"
    },
    {
      "Id": "31553f43-2802-475b-a2b6-aab281d7ba2e",
      "EmployeeId": "46544fa0-5c07-41b2-92bd-3a38d8c2f060",
      "Manufacturer": "Nissan",
      "Fuel": "Gasoline"
    }
  ]
}

For the sake of simplicity, we only show the first record, but we can clearly see that our functionality is working.

Which Bogus Extensions Are Worth Adding?

AutoBogus is the extension most people ask about. It adds AutoFaker<T>, which fills every property of a class without a RuleFor() for each one, and we can still add rules for the properties we care about.

Before we add it, keep in mind that the original AutoBogus package has had no release since July 2021. It still installs and runs on .NET 10 next to the current Bogus, but nobody is fixing it.

Also, “fills every property” means random values of the right type. Without rules, our YearsOld came back as -1987255421 and FirstName as a random word. Realistic names come from the separate AutoBogus.Conventions package.

If we like the AutoBogus model but want a maintained package, Soenneker.Utils.AutoBogus is an active alternative that targets .NET 10 and keeps AutoFaker<T>.

For a handful of classes, plain Bogus rules like ours are still the clearer choice.

The AutoBogus repository still documents both packages, including how to switch the conventions on.

Some of the other popular extensions include:

  • NaughtyStrings.Bogus: a list of strings that have a high probability of breaking our system
  • NodaTime.Bogus: support for the NodaTime library, which we cover in our guide to Noda Time in C#
  • CountryData.Bogus: different records for country-related information like currency, capital, and postcodes

And if we’d rather not write rules at all in our tests, AutoFixture takes that approach from the other side: it builds whole objects from their types.

Conclusion

In this article, we have learned how to use the Bogus library to generate fake data and save us some time.

On top of that, we learned how to generate nested objects realistically, make them repeatable with a seed, and save them to an EF Core database with UseSeeding(). Now, we shouldn’t have any problems when testing our applications with a greater number of records.

Lastly, we went through the additional extensions on top of Bogus to make our coding even easier.

Tested with the .NET 10 SDK (10.0.302), Bogus 35.6.5 and EF Core 10.0.13.