Data Generator. Give it a ⭐ if you find it useful.
Construct a property value using just generated values from the same object.
// Given: FirstName and LastName are randomly generated. The email is dynamically constructed.
.Property(s => s.Email).Construct(s => $"{s.FirstName}.{s.LastName}@mycompany.com")
Support placeholders for numbers, oneofs, resources, and file content, replacing them with values from the corresponding list.
A template like:
"Note: [number:100-999] [resource:Firstnames] [file:lastnames.txt:4-10] [oneof:Europe,America,Africa]"
could generate an output such as: Note: 137 Jessica Torres Africa
.
Note
Specifying a range for numbers is required.
Note
The built-in Length(min, max)
method is ignored when using templates.
Enhance the just generated random value using decorators.
.Property(s => s.Name)
.Template("[resource:Nouns]")
.Decorate(r => CapitalizeFirstLetter(r?.ToString()))
Define rules for generating values, each associated with a probability.
// Generates a negative value in the range of [-5, -1) with a probability of 0.1 (10%).
.Property(s => s.Year)
.Range(1,5)
.GenerationRule("NegativeYear", 0.1, _ => Random.Shared.Next(-5, -1))
Note
The probability of using the default generation logic (Pd) — when no specific generation rules apply — is calculated as: Pd = 1 - ΣPi. Where Pi represents the probability of each individual generation rule.
Defines the probability of assigning a null value.
Note
The property type must be either nullable (T?
) or a reference type with nullable annotations enabled (?
).
// Precondition
class Student
{
public string? FirstName {get; set; }
public string LastName {get; set; }
}
// Great job :)
.Property(s => s.FirstName)
.Template("[file:firstnames.txt]")
.Nullable(0.25)
// Will throw an exception :(
.Property(s => s.FirstName)
.Template("[file:lastnames.txt]")
.Nullable(0.25)
Choose a value from the predefined collection.
.Property(s => s.Degree)
.FromCollection(["Bachelor", "Master", "Doctor"])
Excludes the property from the generation process.
scheme.ForType<StudentGroup>()
.Ignore(s => s.CourseTeachers)
// A custom generator should inherit from `GeneratorBase<T>`
public class PhoneGenerator : GeneratorBase<string>
{
private const char SpecialSymbol = '#';
public override string CreateRandomValue(Property property)
{
var mask = property.GetValueRule("PhoneMask") ?? "### ### ###";
var builder = new StringBuilder();
Random random = GetRandomInstance(property);
foreach (var c in mask.ToString()!)
builder.Append(c != SpecialSymbol ? c : random.Next(0, 10).ToString());
return builder.ToString();
}
}
// Usage
.Property(s => s.Phone)
.UseGenerator(new PhoneGenerator())
.ValueRule("PhoneMask", "## ## ## ##")
BooleanGenerator
DateTimeGenerator
DateTimeOffsetGenerator
DecimalGenerator
DoubleGenerator
EmailGenerator
EnumGenerator
GuidGenerator
IntGenerator
IpGenerator
PhoneGenerator
SetGenerator
StringGenerator
var scheme = new DataScheme();
//StudentGroup
scheme.ForType<StudentGroup>()
.Ignore(s => s.CourseTeachers)
.Property(s => s.Name).Template("[resource:Nouns]").Decorate(r => Utility.CapitalizeFirstLetter(r?.ToString()))
.Property(s => s.Students).Count(3, 5)
.Property(s => s.ContactPhones).Count(2, 3).UseGenerator(new PhoneGenerator());
//Student
scheme.ForType<Student>()
.Property(s => s.FirstName).Template("[resource:Firstnames:3-4]")
.Property(s => s.LastName).Template("[file:lastnames.txt]:4-6").Nullable(0.25)
.Property(s => s.Email).Construct(s => $"{Utility.BuildNameWithoutSpaces(s.FirstName, s.LastName)}" +
$"{TemplateProcessor.CreateValue(Random.Shared,"@[resource:Domains]")}")
.Property(s => s.BirthDay).Range(DateTime.Today.AddYears(-60), DateTime.Today.AddYears(-16)).Nullable(0.1)
.Property(s => s.Year).Range(1,5).GenerationRule("NegativeYear", 0.5, _ => Random.Shared.Next(-5, -1))
.Property(s => s.Courses).Count(2,4)
.Property(s => s.Degree).FromCollection(["Bachelor", "Master", "Doctor"])
.Property(s => s.Note).Template("Note: [number:100-999] [resource:Firstnames] [file:lastnames.txt] [oneof:Europe,America,Africa].");
//Contact
scheme.ForType<Contact>()
.Property(s => s.Phone).UseGenerator(new PhoneGenerator()).PhoneMask("## ## ## ##")
.Property(s => s.Address).Template("[resource:Addresses]")
.Property(s => s.IpAddress).UseGenerator(new IpGenerator()).Nullable(0.5);
var dataGenerator = new SimpleDataGenerator(scheme);
var randomStudentCollection = dataGenerator.GenerateForType<StudentGroup>();
The range default values can be overriden if necessary.