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
Id
field gets value in form of the newGuid
, which is different for each object - The
EmployeeId
field is set through theemployeeId
input parameter - The
Manufacturer
field uses theVehicle
dataset from theFaker
class, and creates different manufacturers for each object - Similarly, the
Fuel
field gets the value with theFuel()
method from the BogusVehicle
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
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.
Have you tried seeding database using this code? It will not work due to the EF quirks. What I had to do to make this work though it’s basically the same was to firstly create Employees without any Vehicles and then in OnModelCreating method I iterated over the Employees collection and for each one of them created collection of Vehicles which then were attached to each Employee. Then it worked.
Hey PDC,
Thanks for reading the article 🙂
Your comment is on point. Indeed, there are things that need to be done in order to seed the database with this code.
However, you can see that we mentioned this inside the Fetching Data from EF Core Database section –
“To avoid having the navigation type of error when seeding the database, we need to initialize our
Employees
andVehicles
without navigation properties.”That said, you can check the source code inside our GitHub repo and see that modifications mentioned are already done 🙂