In this article, we are going to learn what Bogus library is and how we can use it to generate fake data in .NET. We will create examples for generating data in different ways and show some additional community extensions we can use on top of Bogus.

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

Let’s get going.

What is Bogus?

Bogus is a fake data generator for .NET, which we can use to generate simple, but realistic data. It is based on the faker.js library, which is very popular in the JS world, and it is widely used for generating massive amounts of fake data. Syntactically, Bogus is inspired by Fluent Validation, and we will see a lot of similarities when configuring Bogus in C#.

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!

.NET languages like F# and VB.NET also have support for Bogus, but mostly, we use it with C#.

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 fields, we can use those fields to generate Email for that object. That way, our data will look better when we display it.

Bogus has a wide specter 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:

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 fields like Id, FirstNameLastNameAddress, etc. However, we also have the Personality enum:

public enum Personality
{
    Positive,
    Negative,
    Neutral
}

And the list of Vehicle objects per each employee:

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 add package 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.

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 a generic class for which we are specifying the rules, in this case, the Vehicle class. We specify a different rule for each field of the Vehicle class, with the RuleFor() method.

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

  • The Id field gets value in form of the new Guid, which is different for each object
  • The EmployeeId field is set through the employeeId input parameter
  • The Manufacturer field uses the Vehicle dataset from the Faker class, and creates different manufacturers for each object
  • Similarly, the Fuel field 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 NameAddressInternet 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 field for each different Employee.

In our case, we only use a couple of datasets that Bogus is offering, however, there are many more, like Address, 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 = new();
public static readonly List<Vehicle> Vehicles = new();

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 FirstNameLastName and the Email values, it all makes sense. Apparently, our first employee is a fan of Nissan.

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 on the console. That’s enough for us to confirm that the data looks good.

Seeding 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 Entity Framework Core packages, and you can find more about the process in our EF Core series. Once that is done, let’s create a DbContext and override the OnModelCreating() method:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<Employee>().HasData(DataGenerator.Employees);
    modelBuilder.Entity<Vehicle>().HasData(DataGenerator.Vehicles);
}

Here, we use the HasData() method to populate Employee and Vehicle tables with EF Core.

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

Fetching Data from EF Core Database

Next, we should modify our previous code to make it work with Entity Framework. To avoid having the navigation type of error when seeding the database, we need to initialize our Employees and Vehicles without navigation properties. That said, our Employee records shouldn’t have the Vehicles field populated. To fix that, let’s remove our Vehicles related RuleFor() method in the GetEmployeeGenerator():

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>());
}

And add a new line to the end of the InitBogusData() method, to populate Vehicles list:

generatedEmployees.ForEach(e => Vehicles.AddRange(GetBogusVehicleData(e.Id)));

Then, remove the line for adding Vehicle data to Vehicles from the GetBogusVehicleData() method.

Finally, let’s add a new method to the DataGenerator class, to execute the migration and fetch the seeded data from the database:

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

    employeeDbContext.Database.EnsureCreated();

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

    return dbEmployeesWithVehicles;
}

In the GetSeededEmployeesFromDb() method, we initialize a new context and call the EnsureCreated() method, to create our database with seeded data if it is not created. 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:

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.

Bogus Community Extensions

Because of the Bogus popularity, there are a couple of Bogus community extensions worth mentioning. In this way, we can find open-source examples and improvements on top of the Bogus library.

One of the most popular ones is the AutoBogus library. AutoBogus is a C# library that is complementing the Bogus generator. Additional functionalities like auto-creation and population are available with AutoBogus. Useful automatic conventions for data-type detection are available and can provide even more meaningfully generated data. Moreover, we can combine Bogus with AutoBogus to avoid defining all of the specific rules for each different object. Instead, AutoBogus will specify some of the rules for us, and automatize the data generation even further.

Some of the other popular extensions include:

  • NaughtyStrings.Bogus – list of strings that have a high probability of breaking our system
  • NodaTime.Bogus – support for NodaTime library
  • CountryData.Bogus – different records for Country related information like currency, capital, and postcodes

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 and combine our generated data with Entity Framework Core. 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.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!