Dynamically Create Test Data with NBuilder, JSON and .Net October 24, 2010
Posted by ActiveEngine Sensei in .Net, ActiveEngine, Ajax, ASP.Net, C#, Fluent, LINQ, Open Source, Problem Solving.Tags: C#, DataBuilder, How To, JSON.Net, NBuilder, Tutorial
trackback
Part 1 of a 3 part series. For the latest DataBuilder capabilities, read this post or download the new source code from here.
Building test data should be as easy:
var agentList = Builder<SalesAgent>.CreateListOfSize(5) .WhereTheFirst(1) .Have(x => x.FirstName = "James") .And(x => x.LastName = "Kirk") .AndTheNext(1) .Have(x => x.FirstName = "Bruce") .And(x => x.LastName = "Campbell") .Build() .ToList();
Wouldn’t be nice if all the properties of your objects were automatically populated:
Product: Id : 1 Title : "Title1" Description : "Description1" QuantityInStock : 1
NBuilder by provides you with a great fluent interface to accomplish this with ease. You can even achieve scenarios where you can create hierarchies of data, set property values on a range objects in a list, and even create a specified range of values that you can use populate other objects. Peruse through the samples and you will see, NBuilder quite capably maps values the public properties of your objects. A real time saver.
Sensei is going to kick it up a notch and provide you with a means to create test data with out having to recompile your projects. This is ideal for when you want to create UI prototypes. DataBulider uses CS-Script and NBuilder to create a web based data generation tool that can read assemblies and will allow you to script a process that will generate test data in the form of JSON.
This adventure is split into two parts. First a quick demo, then instructions on how to configure DataBuilder for you environment. A deeper discussion of CS-Script and embedded scripting in .Net will be part of the sequel to this action/adventure, as we all know the second movie in the series is always the best!.
Operating DataBuilder
In short you have three things to do:
- Identify the assemblies that contains the objects you want to generate test data for. The path to the files can be anywhere on your system. For convenience there is an folder called Assembly that you can copy the files to. Multiple assemblies from different locations can be imported.
- Create the import statements.
- Create the code snippet with the NBuilder statements that will generate your data.
Here’s a screen shot of DataBuilder with each section that corresponds with the three goals stated above.
And here is an example that we’ll be working with.
var agents = Builder<SalesAgent>.CreateListOfSize(5) .WhereTheFirst(1) .Have(x => x.FirstName = "James") .And(x => x.LastName ="Kirk") .AndTheNext(1) .Have(x => x.FirstName = "Bruce") .And(x => x.LastName = "Campbell"}) .Build() .ToList(); parameters["JsonDataSet"] = JsonConvert.SerializeObject(agents);
Note that after the end of the code that creates the objects, you need to include a statement
parameters["JsonDataSet"] = JsonConvert.SerializeObject(List);
Without that statement you will not get your data serialized. If you’ve entered the data as shown, hit the Build button and the resulting JSON is placed in the output box. That’s it. Looking through the output you’ll note that the first two sales dudes are James Kirk and Bruce Campbell, while the remaining records are completed by NBuilder.
[{"FirstName":"James","LastName":"Kirk","Salary":1.0,"RegionId":1,"RegionName":"RegionName1","StartDate":"\/Date(1287892800000-0400)\/"},{"FirstName":"Bruce","LastName":"Campbell","Salary":2.0,"RegionId":2,"RegionName":"RegionName2","StartDate":"\/Date(1287979200000-0400)\/"},{"FirstName":"FirstName3","LastName":"LastName3","Salary":3.0,"RegionId":3,"RegionName":"RegionName3","StartDate":"\/Date(1288065600000-0400)\/"},{"FirstName":"FirstName4","LastName":"LastName4","Salary":4.0,"RegionId":4,"RegionName":"RegionName4","StartDate":"\/Date(1288152000000-0400)\/"},{"FirstName":"FirstName5","LastName":"LastName5","Salary":5.0,"RegionId":5,"RegionName":"RegionName5","StartDate":"\/Date(1288238400000-0400)\/"}]
You also can load a script and execute it as well. That’s done on the “Script Loader” tab. The location of the scripts is set in the WebConfig and the key name is ScriptPath. Here’s the screen shot:
Anatonomy of DataBuilder Script
Here’s the complete C# script file that builds your data. It’s just a class:
//CSScript directives - DO NOT REMOVE THE css_ref SECTION!!! //css_ref System.Core; //css_ref System.Data.ComponentModel; //css_ref System.Data.DataSetExtensions; //css_ref System.Xml.Linq; using System; using System.Collections.Generic; using System.Text; using System.IO; using DataGenerator.Core; using DataGenerator.ObjectTypes; using DataGenerator.ScriptHost; using System.Linq.Expressions; using System.Linq; using Newtonsoft.Json; using FizzWare.NBuilder; // Add a reference to your assemblies as well!! using UserDeploymentDomain; public class CreateTestFile : IScriptRunner { public void RunScript(Dictionary parameters) { var agents = Builder.CreateListOfSize(5) .WhereTheFirst(1) .Have(x => x.FirstName = "James") .And(x => x.LastName = "Kirk") .AndTheNext(1) .Have(x => x.FirstName = "Bruce") .And(x => x.LastName = "Campbell") .Build() .ToList(); parameters["JsonDataSet"] = JsonConvert.SerializeObject(agents); } public void RunScript() { throw new NotImplementedException(); } }
The very top section “CSScript Directives” is required by CS-Script. These are directives that instruct the CS-Script engine to include assemblies when it compiles the script. The imports section is pretty straight forward.
You’ll note that the script inherits from an interface. This is a convention used by CS-Script to allow the host and script to share their respective assemblies. Sensei will discuss that in next post. The RunScript method accepts a Dictionary that contains the parameters. This will house the JsonDataSet that is expected for the screen to display the output of your data.
Advanced NBuilder Experiments
The beauty of NBuilder is that you can create test data that goes beyond “FirstName1”, and allows you to quickly create data that matches what the business users are used to seeing. If you think about it you should be able to generate test data that will exercise any rules that you have in the business domain, such as “Add 5% tax when shipping to New York”. With the scripting capability of DataBuilder you can create suites test data that can evolve as you test your system. You could also use the JsonDataSet to create mocks of your objects as well, maybe use them for prototyping your front end.
We’ll do a quick sample. Our scenario is to create assign real regions to sales agents. Furthermore, we want to only chose a range of regions and assign them at random.
First we build the Regions:
var regions= Builder<Region>.CreateListOfSize(4) .WhereTheFirst(1) .Have(x => x.State = "Texas") .AndTheNext(1) .Have(x => x.State = "California") .AndTheNext(1) .Have(x => x.State = "Ohio") .AndTheNext(1) .Have(x => x.State = "New York") .Build();
Now we’ll create a SalesAgents and using the Pick method from NBuilder we’ll randomly assign a region to the sales agents:
var agents = Builder<SalesAgent>.CreateListOfSize(5) .WhereAll() .HaveDoneToThem(x => x.RegionName = Pick.RandomItemFrom(regions).State) .WhereTheFirst(1) .Have(x => x.FirstName = "James") .And(x => x.LastName = "Kirk") .AndTheNext(1) .Have(x => x.FirstName = "Bruce") .And(x => x.LastName = "Campbell") .Build() .ToList();
The result set now has the range of states distributed to the Sales Agents. Looks like James Kirk needs to cover Texas. You may need to view the source to see the output.
[{"FirstName":"James","LastName":"Kirk","Salary":1.0,"RegionId":1,"RegionName":"Texas","StartDate":"\/Date(1287892800000-0400)\/"},{"FirstName":"Bruce","LastName":"Campbell","Salary":2.0,"RegionId":2,"RegionName":"Texas","StartDate":"\/Date(1287979200000-0400)\/"},{"FirstName":"FirstName3","LastName":"LastName3","Salary":3.0,"RegionId":3,"RegionName":"California","StartDate":"\/Date(1288065600000-0400)\/"},{"FirstName":"FirstName4","LastName":"LastName4","Salary":4.0,"RegionId":4,"RegionName":"California","StartDate":"\/Date(1288152000000-0400)\/"},{"FirstName":"FirstName5","LastName":"LastName5","Salary":5.0,"RegionId":5,"RegionName":"Ohio","StartDate":"\/Date(1288238400000-0400)\/"}]
Configure DataBuilder For Your Environment
Given that DataBuilder is loading assemblies you will want to run it on either your dev environment or on a test server where your co workers won’t mind if you need to take IIS up and down. Also, you’ll want to work with a copy of your assemblies in case you need to make a quick change. There are times when IIS will not release a file and if you need to make changes to the assemblies themselves it’s more convenient to copy them after you’ve re-compiled.
There are two settings you need to change in the WebConfig to match your environment.
ScriptPath – Point this to the share where you want to save any scripts. DataBuilder will scour the directory and list anything you place in there.
FizzWarePath – This needs to point to the location of the NBuilder dll. Most likely this will be the bin folder of the DataBuilder website. In the follow up post Sensei will explain what this does.
Wrapping Up For Now
We covered a lot on the whirlwind tour of DataBuilder. There’s a lot more that is of interest, particularly with respects to the embedded scripting aspects provided by CS-Script. For now, have fun playing building you data sets. In the next installment we’ll cover the scripting aspect in more detail For now, download and experiment. Here’s the source for DataBuilder with unit tests.
[…] This post was mentioned on Twitter by Richard Laksana, LINQ Feeds. LINQ Feeds said: Dynamically Create Test Data with NBuilder, JSON and .Net http://bit.ly/clOdyu […]
[…] Last episode Sensei unveiled a useful little tool called DataBuilder. DataBuilder helps you to generate test data for you domain objects. Just point DataBuilder to your assemblies, and with the magic of NBuilder, CS-Script you can create test data as JSON. How is this possible? This post will focus on the behind the scenes magic that makes DataBuilder so flexible. […]
Nice and simple code thanks for sharing
@anehra63 – Glad this can be of use to you. My goal with these projects is to automate the tasks that can consume too much time. If I have to compile less, deploy less and can prototype quickly my overall goals on larger projects can stay in focus. If you have questions or issues please let me know.
[…] you have been following the series on DataBuilder, a utility that dynamically creates test data as JSON, you’ll recall one of the highlights […]