|
|||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionI wanted to write a framework and GUI that allowed me to quickly write and use various sample data generators. I'm constantly writing small console applications to create random, but real-world sample data for pre-populating database applications during testing, or for writing unit-tests against. This project sets out to achieve the following goals:
IDataGenerator<T> InterfaceAll sample data generators that fit into this framework implement the generic public interface IDataGenerator<T>
{
void Setup();
void TearDown();
T Next();
List<T> Next(int count);
string ToString(T value);
string[] ToStringArray(List<T> values);
}
Each method is described here: SetupThis method should setup the data generator ready to be called. For example, in the Names generator, TeardownThis method should clean-up memory and resources the data generator might have initialized in NextThis is the main method that generates a single instance of sample data. The Next(count)This method calls public List<T> Next(T count)
{
List<T> result = new List<T>(count);
for (int i = 0; i < count; i++)
result.Add(Next());
return result;
}
ToString(value)This method allows you to format and control how each data generator will return as a ToStringArray(List<T>)Returns a public string[] ToStringArray(List<int> values)
{
List<string> result = new List<string>(values.Count);
foreach(int i in values)
result.Add(ToString(i));
return result.ToArray();
}
By adhering to this interface, using a data generator follows the pattern call public List
This might be useful for unit testing, but I also wanted to be able to easily run them from a graphical user interface application that allowed generators to be easily added. I have written a step-by-step document on how to write new plug-in Data Generators, which takes you through the process of building the The Sample Data Generator GUI ApplicationMy goal for the GUI application was to allow new generators to be discovered if I dropped their assembly into the same folder that the GUI application was running from. I didn't want to have to edit config files. I also needed the GUI to dynamically handle different properties that customize the generation process. For example, when generating I took the following approach:
There is actually very little code to all of this, mainly due to the fully featured To expose a class to the GUI harness, we simply add an [DataGeneratorAttribute(Name = "Integers", ReturnType =
typeof(int), Description = "Generates random integer values.")]
public class IntegerGenerator : IDataGenerator<int>
{
The properties are mostly self-explanatory, Here is the code which finds all of the private void findAllDataGenerators(string path)
{
string[] files = Directory.GetFiles(path, "*.dll");
foreach (string file in files)
{
Assembly a = Assembly.LoadFile(file);
Type[] types = a.GetTypes();
foreach(Type t in types)
{
object[] attributes = t.GetCustomAttributes
(typeof(Aspiring.DataGenerator.DataGeneratorAttribute), true);
if (attributes.Length == 1)
{
DataGeneratorInfo g = new DataGeneratorInfo();
g.Assembly = a;
g.DataGeneratorType = t;
g.Attribute = (DataGeneratorAttribute)attributes[0];
generators.Add(g);
}
}
}
}
The code which creates an instance of our Data Generator once the user has chosen one and assigns it to a // construct the generator and connect it to the property grid
currentDataGeneratorInfo =
(DataGeneratorInfo)listBoxGenerators.Items[listBoxGenerators.SelectedIndex];
Type t = currentDataGeneratorInfo.DataGeneratorType;
currentGenerator = Activator.CreateInstance(t);
propertyGrid.SelectedObject = currentGenerator;
The [Description("The minimum age allowed for the birthdate.
Must be less than MaxAge.")]
public int MinAge
{
get { return _minAge; }
set
{
if (value > MaxAge)
throw new ArgumentOutOfRangeException
("MinAge", "MinAge must be less than or equal to MaxAge." );
_minAge = value;
}
}
The final step is to actually get the generators to do their job, create sample data and format it on the screen. Formatting is pretty crude at the moment, I've hard-coded a few common ways but think some kind of formatters might be useful here; off the top of my head I'd like it to generate database scripts, XML files, just to name a few. VB support might also be useful, but for now, my needs are met. I just need IEnumerable q;
currentGenerator.GetType().InvokeMember("Setup", BindingFlags.InvokeMethod |
BindingFlags.Instance | BindingFlags.Public, null, currentGenerator,
new object[] {});
try
{
q = (IEnumerable)currentGenerator.GetType().InvokeMember
("Next", BindingFlags.InvokeMethod | BindingFlags.Instance |
BindingFlags.Public, null, currentGenerator, new object[] {count});
}
finally
{
currentGenerator.GetType().InvokeMember("TearDown",
BindingFlags.InvokeMethod | BindingFlags.Instance |
BindingFlags.Public, null, currentGenerator, new object[] {});
}
One point to note is that I wrapped the The GUI application makes heavy use of reflection, but the whole GUI main form is less than 200 lines. The built-in support for databinding to list-boxes and property-grids made my job really easy. Current Data GeneratorsI now need to move all of my sample data generators into this new interface, but I have managed to do the first couple of big ones. I'm certain there will be more to come and I'd be interested in yours should you use this interface and framework. Keep an eye on my blog and I'll also post comments here. Birthdates (or any date really), you can specify a Format string (based on .NET Lorem Ipsum: You know, that random looking text used as filler when laying out a page. You can specify how many paragraphs to build. Integers: Numbers, no decimal places between a given Min and Max value. People's names. The Name generator uses census data to build real world names and salutations, and by using a property called FormatString you can specify exactly how you want the resulting name to look. This makes it easy for me to build names quickly and efficiently in any style or capitalization. The following placeholders will be replaced by name data:
For example: This generator is BIG because of the census data that gives real names to choose from. There is a size limit on code project, so you will need to download it from my blog here. History
|
||||||||||||||||||||||||||||||||||||||||