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.
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#.
.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, 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:
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Ā
Idfield gets value in form of the newĀGuid, which is different for each object - TheĀ
EmployeeIdfield is set through theemployeeIdinput parameter - TheĀ
Manufacturerfield uses theĀVehicledataset from theFakerclass, and creates different manufacturers for each object - Similarly, theĀ
Fuelfield gets the value with theFuel()method from the BogusVehicledataset
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 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Ā FirstName,Ā LastName 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 systemNodaTime.Bogus– support for NodaTime libraryCountryData.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.
