Spargine is a collection of open-source assemblies and NuGet packages designed for .NET 10, which I have been developing and maintaining since the release of .NET Framework 2. These assemblies are not only a core part of my projects but are also actively deployed in production environments across several companies I collaborate with.
Get Spargine
You can access the source code and NuGet packages here:
- GitHub: Spargine 10
- NuGet: dotNetDaveNuGet
In 2019, while developing benchmark tests for the first edition of my code performance book, I needed realistic “real-world” data types—such as people, addresses, and coordinates—along with utilities to generate random words, email addresses, URLs, and more. Once that work was complete, it became clear that this functionality was far too useful to live only inside a single book project.
I consolidated the code into its own assembly and, recognizing its broader applicability, published it as a NuGet package so it could be reused across unit tests, benchmark projects, and real-world applications.
With the arrival of .NET 10, the assembly—now released as DotNetTips.Spargine.Tester—has seen significant enhancements. Its core mission remains the same: make it easy to generate realistic data and domain objects for testing and benchmarking. New features include benchmark-friendly helpers (such as fixed-length string generators) and expanded support for real-world data scenarios. This assembly is now actively used across multiple production and professional projects.
Person Types
For the benchmark tests in my performance book, I designed a Person type that demonstrates best practices in API design, implementation, and documentation. In the latest version of the package, the original reference-type Person has been expanded into three variants:
- Reference type (RefTypes.Person)
- Value type (ValueTypes.Person)
- Record type (PersonRecord)
All implementations conform to the IPerson interface, making it easy to compare performance characteristics across representations.
Constructor
- Person(string email, string id)
Initializes a new instance of the class with the specified email and id.
Properties
| Addresses | BornOn | CellPhone |
| FirstName | Id | |
| LastName | Phone | |
Methods
- Create(string id, string email, string firstName, string lastName, DateTimeOffset? bornOn, Collection<Address>? addresses, string? cellPhone, string? phone)
Creates a new Person with the specified values. - ToPerson(Person person)
Converts Person to ValueTypes.Person. - ToPerson(PersonRecord person)
Converts PersonRecord to a Person. - ToPerson(ValueTypes.Person person)
Converts ValueTypes.Person to Person. - ToString()
Returns a string representation of the Person.
To further improve performance, a dedicated JsonSerializerContext is included for optimized serialization and deserialization of individual Person instances and collections.
PersonExtensions
This version of the assembly introduces extension properties for the Person types:
- FullName
Gets the full name of the person by concatenating the first and last names. - Age
Gets the age of the person as a TimeSpan since their birth date.
Address Types
Address types represent structured address data, including street information, city, state, country, postal code, and phone number. All address implementations—including record variants—implement the IAddress<TSelf> interface.
Constructors
- Address(string id)
Initializes a new instance of the class with the specified identifier. - Address(string id, string address1, string city, string country, string postalCode)
Initializes a new instance of the class with the specified identifier, address line 1, city, country, and postal code.
Properties
| Address1 | Address2 | City |
| Country | CountryProvince | Id |
| Phone | PostalCode | State |
Methods
- Create(string Id)
Creates a new Address with only the identifier. - Create(string id, string address1, string city, string country, string postalCode, string? address2, string? countyProvince, string? state, string? phone)
Factory method to create a new Address instance with the specified values. - ToAddress(Address address)
Converts a reference Address to AddressRecord. - ToAddress(AddressRecord address)
Converts an AddressRecord to Address. - ToAddress(ValueTypes.Address address)
Converts a ValueTypes.Address to Address. - ToString()
Returns a human-readable representation of this address instance for diagnostics.
Coordinate Type
To support spatial and numeric benchmarks, the package includes a Coordinate implementation that adheres to the ICoordinate interface, which exposes X, Y, and Z properties. Both reference and value-type implementations are provided to support comparative benchmarking.
Random Data Methods
Randomized input is essential for meaningful tests. Developers often underestimate edge cases—such as last names with apostrophes—that can expose bugs in validation logic or database operations. Humans are poor at generating truly random data, but code excels at it.
The RandomData static class exists to solve this problem. It provides a large and continually expanding set of methods for generating realistic, randomized data. New methods are frequently added as new benchmarking scenarios emerge.
Below is a selection of available methods with representative output.
| Method | Description/ Output |
| GenerateAddress<TAddress>(Country? country, int addressLength, int countyProvinceLength) | Generates an address instance populated with random data for the specified address type. |
| GenerateAddressCollection<TAddress>(int count, int addressLength, int countyProvinceLength = 20) | Generates a collection of addresses for a randomly selected country. This method is overloaded to also use a Country. |
| GenerateByteArray(int count) | Generates a byte array of a specified size filled with cryptographically secure random data. |
| GenerateCharacter() | Generates a random character using the default minimum and maximum character constraints. This method is overloaded to use a char minValue and char maxValue. |
| GenerateCoordinate<T> | Generates a coordinate with random values for X, Y, and Z using the specified T which must implement ICoordinate. |
| GenerateCoordinateCollection<T>(int count) | Generates a collection of coordinates with random values for X, Y, and Z. |
| GenerateCreditCard() | Generates a valid credit card number with a random set of digits and a card type randomly selected from Visa, American Express, Diners Card, Discover, Voyager, JCB, and Enroute. |
| GenerateCreditCards(int count) | Generates a read-only collection of random credit card numbers. |
| GenerateDecimal(in decimal minValue, in decimal maxValue, int decimalPlaces) | Generates a random decimal number within a specified range and with a specified number of decimal places. |
| GenerateDomainExtension() | Generates a random domain extension from a predefined list. Example: .co.uk |
| GenerateEmailAddress() | Generates a random email address. |
| GenerateFile(string fileName, int fileLength) | Generates a file with random content. |
| GenerateFiles(int count, int fileLength, string fileExtension) | Generates a specified number of files with random content, each having a specified length and file extension. |
| GenerateFiles(string path, int count, int fileLength) | Generates a specified number of files with random content at the given path, each having a specified length and file extension. |
| GenerateFirstName() | Generates a random first name from a predefined list from a pool containing over 1,800 names. |
| GenerateInteger(int min, int max) | Generates a random integer within a specified range. |
| GenerateKey() | Generates a random unique key. Example: f7f0af7803d4ab194b5a4024d02112a |
| GenerateLastName() | Generates a random last name from a predefined list from a pool containing over 2,000 names. |
| GenerateNonZeroByteArray(int count) | Generates a byte array of a specified size filled with non-zero cryptographically secure random data. |
| GenerateNumber(int length) | Generates a random number as a string. Example: 446085072052112 |
| GeneratePerson<TPerson>(int addressCount, int addressLength, int countyProvinceLength) | Generates a person of the specified type: RefTypes.Person, ValueTypes.Person, or PersonRecord. |
| GeneratePersonNames(int count) | Generates a collection of PersonName objects. |
| GeneratePersonRecordCollection(int count) | Generates a collection of PersonRecord objects. |
| GeneratePersonRefCollection(int count) | Generates a collection of Person reference objects. |
| GeneratePersonValCollection(int count) | Generates a collection of Person value objects. |
| GeneratePhoneNumber(Country country, bool includeCountryCode) | Generates a random phone number based on a specified country, with the option to include the country code using the includeCountryCode parameter. Example: 1-284-424-2216 |
| GenerateRandomFileName(int fileNameLength, string extension) | Generates a random file name in the temporary path with the specified length and extension. |
| GenerateRandomFileName(string path, int fileNameLength, string extension) | Generates a random file name with the specified length and extension at the given path. |
| GenerateRandomLocationData() | Generates random real location data including country, state, and city. |
| GenerateRandomPersonData() | Generates random person data including first name, last name, and email. |
| GenerateRandomPersonName() | Generates a random person’s last and first name. |
| GenerateRelativeUrl() | Generates a random relative URL. Example: /ljsylu/rsglcuriylqld/wejdbuainlgjofnv/uwbrjftyt/ |
| GenerateTempFile(int fileLength) | Generates a temporary file with random content in the C:\\Users\<user name>\AppData\Local\Temp\ folder. |
| GenerateUrl() | Generates a full URL by combining a randomly generated hostname with a randomly generated relative URL. Example: https://www.rp.red/wyfkxbfft/pqypmdstoydnootvdvnsqkn/ |
| GenerateUrlFragment() | Generate a URL fragment. Example: /rregyyjxpjiats |
| GenerateUrlHostName() | Generates a URL hostname with HTTPS protocol. Example: https://www.ukrsusbrtjijfktfj.shouji |
| GenerateUrlHostnameNoProtocol() | Generates a URL hostname without the protocol. Example: http://www.txtkixvsxgryixbwrtje.shangrila |
| GenerateUrlHostnameNoSubdomain() | Generates a URL hostname without the protocol by using a randomly generated domain extension. Example: dz |
| GenerateWord(int length) | Generates a word of the specified length. Example: mL_g[E_E_CsoJvjshI]cFjFKa |
| GenerateWord(int minLength, int maxLength) | Generates a word with a random length within the specified range. Example: anvpwufadtxpfysguavguwm |
| GenerateWord(int length, char minCharacter, char maxCharacter) | Generates a word of the specified length using characters within the specified range. Example: aLBEEUMHHHK |
| GenerateWord(int minLength, int maxLength, char minCharacter, char maxCharacter) | Generates a word with a random length within the specified range and character limits. Example: ACRNFTPAE |
| GenerateWords(int count, int minLength, int maxLength) | Generates a collection of random words. Example: [0]:“oKcMYETNvpiByRQVa” [1]:“mnM\\wQwuluQ^VFxpOJEgL” [2]:“Ad\\kCOMkmd” |
| Property | Description |
| LongTestString | Provides a comprehensive string tailored for testing purposes, comprising 969 characters, inclusive of spaces. |
Realistic Person and Address Information
The Person and Address generation logic has been enhanced so that most data—excluding Address1 and Address2—is generated in a country-aware manner. The process randomly selects a country, then derives valid states, cities, phone numbers, and postal codes based on that country. First names, last names, and email addresses are generated to reflect real-world patterns.
As a result, generated data now closely resembles actual production data, making it far more valuable for realistic testing, demos, and benchmarks.
Future work includes improving the realism of Address1 and Address2, which is planned but intentionally deferred.
{
"Address1": "yB[kEjKkUqcQLxG][odoUcIEy",
"Address2": "CnsfNH^tL_YWN^Fb[ca\\pfZFi",
"BornOn": "1957-04-09T16:08:45.8948496-07:00",
"CellPhone": "3140713855",
"City": "Floridsdorf",
"Country": "Austria",
"Email": "Courtney.Coronado@vemyy.shoes",
"FirstName": "Courtney",
"HomePhone": "0258058628",
"Id": "1c88785618f84e73b5e07172adb63f93",
"LastName": "Coronado",
"PostalCode": "5888",
"State": "Vienna"
}
Country Data and Lookup
This assembly includes country, state, and city data for all countries worldwide, accessible through the CountryRepository.
var countries = Countries.GetCountries();
These are the class models that will be returned.
Additional retrieval methods include:
- GetCountry(CountryName countryName)
Retrieves country information based on a value from the CountryName Enum. - GetCountry(string countryNameOrIso)
Retrieves a country by its name or ISO code.
RandomCreditCardNumberGenerator
The RandomCreditCardNumberGenerator produces realistic, valid credit card numbers suitable for testing (not real accounts).
Available methods include:
- GetCreditCardNumber()
Generate a single random credit card number. Supported credit cards include: American Express, Diners Club, Discover, EnRoute, JCB, MasterCard, Visa, and Voyager. - GetCreditCardNumbers(int count)
Generates a collection of random credit card numbers. Supported credit cards include: American Express, Diners Club, Discover, EnRoute, JCB, MasterCard, Visa, and Voyager.
Summary
The DotNetTips.Spargine.Tester assembly removes the friction from creating realistic, repeatable, and benchmark-friendly test data. Whether you’re writing unit tests, building performance benchmarks, validating edge cases, or demonstrating real-world scenarios, this library gives you a rich set of tools to generate meaningful data quickly and consistently.
By offering reference types, value types, and records side by side, the package also enables precise performance comparisons—making it especially valuable for benchmarking and performance-focused development. The inclusion of country-aware data, optimized serialization contexts, and cryptographically secure randomness further elevates it beyond simple “fake data” generators.
Finally, be sure to explore the UnitTester utilities included in this assembly, which add even more capabilities to your unit testing workflow. Together, these tools help you write better tests, run more accurate benchmarks, and build more resilient .NET applications with confidence.
Get Involved!
The success of open-source projects like Spargine relies on community contributions. If you find these updates useful or have ideas for further improvements, I encourage you to contribute by:
- Submitting pull requests
- Reporting issues
- Suggesting new features
Your input is invaluable in making Spargine an even more powerful tool for the .NET community.
If you are interested in contributing or have any questions, feel free to contact me via email at dotnetdave@live.com. Your support and collaboration are greatly appreciated!
Thank you, and happy coding!



Pick up any books by David McCarter by going to Amazon.com: http://bit.ly/RockYourCodeBooks
Make a one-time donation
Make a monthly donation
Make a yearly donation
Choose an amount
Or enter a custom amount
Your contribution is appreciated.
Your contribution is appreciated.
Your contribution is appreciated.
DonateDonate monthlyDonate yearlyIf you liked this article, please buy David a cup of Coffee by going here: https://www.buymeacoffee.com/dotnetdave
© The information in this article is copywritten and cannot be preproduced in any way without express permission from David McCarter.
Discover more from dotNetTips.com
Subscribe to get the latest posts sent to your email.


