I’ve visited this topic (briefly) in the past using NBuilder and AutoFixture.
When writing unit tests it would be useful if we can create objects quickly and with random or better still semi-random data.
When I say semi-random, what I mean is that we might have some type with an Id property and we know this Id can only have a certain range of values, so we want a value generated for this property within that range, or maybe we would like to have a CreatedDate property with some data that resembles n years in the past, as opposed to just random date.
This is where libraries such as Faker.Net and Bogus come in – they allow us to generate objects and data, which meets certain criteria and also includes the ability to generate data which “looks” like real data. For example, first names, jobs, addresses etc.
Let’s look at an example – first we’ll see what the “model” looks like, i.e. the object we want to generate test data for
public class MyModel { public string Name { get; set; } public long Id { get; set; } public long Version { get; set; } public Date Created { get; set; } } public struct Date { public int Day { get; set; } public int Month { get; set; } public int Year { get; set; } }
The date struct was included because this mirrors a similar type of object I get from some web services and because it obviously requires certain constraints, hence seemed a good example of writing such code.
Now let’s assume that we want to create a MyModel object. Using Bogus we can create a Facker object and apply constraints or assign random data to. Here’s an example implementation
var modelFaker = new Faker<MyModel>() .RuleFor(o => o.Name, f => f.Name.FirstName()) .RuleFor(o => o.Id, f => f.Random.Number(100, 200)) .RuleFor(o => o.Version, f => f.Random.Number(300, 400)) .RuleFor(o => o.Created, f => { var date = f.Date.Past(); return new Date { Day = date.Day, Month = date.Month, Year = date.Year }; }); var myModel = modelFaker.Generate();
Initially we create the equivalent of a builder class, in this case the Faker. Whilst we can generate a MyModel without all the rules being set, the rules allow us to customize what’s generated to something more meaningful for our use – especially when it comes to the Date type. So in order, the rules state that the Name property on MyModel should resemble a FirstName, the Id is set to a random value within the range 100-200, likewise the Version is constrained to the range 300-400 and finally the Created property is set by generating a past date and assigning the day, month and year to our Date struct.
Finally we Generate an instance of a MyModel object via the Faker builder class. An example of the values supplied by the Faker object are shown below
Created - Day = 12, Month = 7, Year = 2016 Id - 116 Name - Gwen Version - 312
Obviously this code only works for classes with a default constructor. So what do we do if there’s no default constructor?
Let’s add the following to the MyModel class
public MyModel(long id, long version) { Id = id; Version = version; }
Now we simply change our Faker to look like this
var modelFaker = new Faker<MyModel>() .CustomInstantiator(f => new MyModel( f.Random.Number(100, 200), f.Random.Number(300, 400))) .RuleFor(o => o.Name, f => f.Name.FirstName()) .RuleFor(o => o.Create, f => { var date = f.Date.Past(); return new Date { Day = date.Day, Month = date.Month, Year = date.Year }; });
What if you don’t want to create a the whole MyModel object via Faker, but instead, you just want to generate a valid looking first name for the Name property? Or what if you are already using something like NBuilder but want to just use the Faker data generation code?
This can easily be achieved by using the non-generic Faker. Create an instance of it and you’ve got access to the same data, so for example
var f = new Faker(); myModel.Name = f.Name.FirstName();
References