Generate Realistic Test Data in Kentico
Introduction
Recently I wanted to play around with some user specific scenarios in my Kentico instance for a presentation that I was working on. To do that I needed a Kentico 9 instance with a lot of various users, user settings, and role associations already setup. After firing up a few instances of Visual Studio and running locally, I realized that I didn't have any good sandboxes to play in. So I bit the bullet, and started down the path of automating the creation of a few hundred users.
I figured that there was no way it would take more than just a few minutes to do this task. It’s just creating a few users in Kentico which is like 4 or 5 lines of code in a for loop, right? As it turns out, there is a good way to do this, and then an even better way to do it using some freely available NuGet packages.
Generating Test Data in an Ok Way
As any good Kentico developer would do, I fired up a fresh instance and started working with the normal UserInfoProvider and UserInfo objects that the Kentico API is famous for. And indeed after a few short minutes I have some really vanilla code to work with.
string siteName = SiteContext.CurrentSiteName; for (int i=0; i<100; i++) { // Creates a new user object UserInfo newUser = new UserInfo(); // Sets the user properties newUser.FullName = "first lastname"; newUser.Email = "test@test.com"; newUser.UserName = newUser.Email; newUser.PreferredCultureCode = "en-us"; newUser.Enabled = true; // Inserts the users to the database UserInfoProvider.SetUserInfo(newUser); //Associates the user to the site UserInfoProvider.AddUserToSite(newUser.UserName, siteName); //Registers analytics for new user registration AnalyticsHelper.LogRegisteredUser(siteName, newUser); }
We’ve all seen code like this before, maybe even in the Kentico 9 API examples that are available. The problem is that in this code the username is hard coded and that generates an error in Kentico the second time through the loop. Also way more importantly, if you correct that error by adding in an unique incrementor to the username, every user basically looks the exact same.
This sample data doesn’t really help me for my needs where I really wanted to look at more realistic data. So on to something better.
Doing it a Much Better Way with Faker.NET
After a bit of internet searching I stumbled upon Faker.NET. This free library is a C# version of a widely used Ruby project called faker. The library allows the user to generate realistic looking names, addresses, phone numbers, emails, locations and more. It’s pretty amazing and available via a simple NuGet package command in .NET.
Install-Package Faker.NET
With this library installed I can now change the guts of the code to:
string siteName = SiteContext.CurrentSiteName; bool logOnlineMarketing = AnalyticsHelper.AnalyticsEnabled(siteName); for (int i=0; i<100; i++) { // Creates a new user object UserInfo newUser = new UserInfo(); // Sets the user properties newUser.FullName = Faker.Name.FullName(); newUser.Email = Faker.Internet.Email(); newUser.UserName = newUser.Email; newUser.PreferredCultureCode = "en-us"; newUser.Enabled = true; // Inserts the users to the database UserInfoProvider.SetUserInfo(newUser); //Associates the user to the site UserInfoProvider.AddUserToSite(newUser.UserName, siteName); if (logOnlineMarketing) { //Registers analytic hit for new user registration AnalyticsHelper.LogRegisteredUser(siteName, newUser); } }
Running this code results in the following set of users being created in the system:
As you can see the faker static objects like .Name.First(), .Name.Last(), .Name.FullName(), and .Internet.Email() are the magic. These objects use some sort of voodoo magic to generate realistic looking names and email addresses. There are tons of options for other objects like locations, phone numbers, and other cool things that you can use to populate just about any kind of normal string value in a web application. Pretty cool eh?
Pro Tip: There is also a great Data Generator for On-line Marketing data already in Kentico 9.
Doing it the Best way with Faker.NET and NBuilder
For loops are so 1970’s right? With all the LINQ rage that is happening today, who wants to write such old school syntax? Enter NBuilder, another third party NuGet package out there. NBuilder allows you to rapidly create test data, automatically assigning values to properties and public fields that are of type of the built in .NET data types (int, string etc). Really both NBuilder and Faker have been around for a long time and are nothing that new, but they were new to me, so I thought I would share.
Again to get the NBuilder package you just have to fire up the NuGet package manager console and run the following command:
Install-Package NBuilder
Utilizing NBuilder gets us to code that looks like this:
string siteName = SiteContext.CurrentSiteName; bool logOnlineMarketing = AnalyticsHelper.AnalyticsEnabled(siteName); //Very important to not jam in auto values that we don't want for NBuilder BuilderSetup.AutoNameProperties = false; //Create the new list of users var users = Builder<UserInfo>.CreateListOfSize(100).All() .With(u => u.FullName = Faker.Name.FullName()) .With(u => u.Email = Faker.Internet.Email()) .With(u => u.UserName = u.Email) .With(u => u.PreferredCultureCode = "en-us") .With(u => u.Enabled = true) .Build(); foreach (UserInfo user in users) { // Inserts the users to the database UserInfoProvider.SetUserInfo(user); //Associates the user to the site UserInfoProvider.AddUserToSite(user.UserName, siteName); if (logOnlineMarketing) { //Registers analytic hit for new user registration AnalyticsHelper.LogRegisteredUser(siteName, user); } }
The reason that I liked NBuilder is the fact that it is a very clean way to generate a list of objects in bulk. It gives you some fluent style syntax and is meant to work with persistent storage (mainly Entity Framework) like the Kentico database. The results of running the code above is exactly the same as the previous example, but cleaner and more readable.
One special note is that if you don't add the AutoNameProperties to false line, NBuilder tries to fill in all the values of the object it can, including things like ObjectID and ObjectGUID. This is bad news for the Kentico API. So make sure you don't forget it.
Another nice bonus of NBuilder is the very nice utility method it has, RandomGenerator(). Using this object allows you to quickly work with a random object to randomize property values. This comes in handy with things like DateTimes and data relationships (think CMS Role associations or CMS Site Associations). Basically you can use code like the following to randomize the create date and/or last logged on date of the users. Again this is all in an effort to have realistic test data in your Kentico site.
var users = UserInfoProvider.GetUsers().WhereEquals("UserPrivilegeLevel", 0); var daysGenerator = new RandomGenerator(); foreach (UserInfo user in users) { user.UserCreated = DateTime.Now.AddDays(-daysGenerator.Next(1, 600)); UserInfoProvider.SetUserInfo(user); }
Running this code will get you a result with not only randomly created names, but also random CreatedOn dates for the users.
Conclusion
All of the kudos do belong to the library authors of Faker.NET, NBuilder, and of course the Kentico API. You could also use this approach for unit testing and automated QA tasks. In fact my QA Specialist at BizStream has been nagging me for months now to create something like this for him when we test our e-commerce sites.
And yes, in case your curious, I do have more of this type of code written to generate registered e-commerce customers, customer addresses, and e-commerce orders. I think it is going to help with proving all of the custom payment gateway and custom tax providers that we write for our e-commerce sites. I'm happy with it at least. I would have relied on the aforementioned data generator in Kentico 9. however it does not generate anything realistic because it hard codes the total price of an order. I wanted to actually use our custom code to do that.
As you can see it is pretty easy to generate large amounts of realistic test data in Kentico without too much effort. Let me know what you think in the comments.