QuickFuzzr 0.1.1
dotnet add package QuickFuzzr --version 0.1.1
NuGet\Install-Package QuickFuzzr -Version 0.1.1
<PackageReference Include="QuickFuzzr" Version="0.1.1" />
<PackageVersion Include="QuickFuzzr" Version="0.1.1" />
<PackageReference Include="QuickFuzzr" />
paket add QuickFuzzr --version 0.1.1
#r "nuget: QuickFuzzr, 0.1.1"
#:package QuickFuzzr@0.1.1
#addin nuget:?package=QuickFuzzr&version=0.1.1
#tool nuget:?package=QuickFuzzr&version=0.1.1
Generating Objects
A simple object.
Use Fuzz.One<T>()
, where T is the type of object you want to generate.
The primitive properties of the object will be automatically filled in using the default (or replaced) generators.
The enumeration properties of the object will be automatically filled in using the default (or replaced) Fuzz.Enum<T> generator.
The object properties will also be automatically filled in using the default (or replaced) generators, similar to calling Fuzz.One<TProperty>() and setting the value using
Apply
(see below) explicitly.Also works for properties with private setters.
Can generate any object that has a parameterless constructor, be it public, protected, or private.
The overload
Fuzz.One<T>(Func<T> constructor)
allows for specific constructor selection.
Ignoring properties.
Use the Fuzz.For<T>().Ignore<TProperty>(Expression<Func<T, TProperty>> func)
method chain.
F.i. :
Fuzz.For<SomeThingToGenerate>().Ignore(s => s.Id)
The property specified will be ignored during generation.
Derived classes generated also ignore the base property.
Sometimes it is useful to ignore all properties while generating an object.
For this use Fuzz.For<SomeThingToGenerate>().IgnoreAll()
IgnoreAll()
does not ignore properties on derived classes, even inherited properties.
**Note π* The Ignore(...)
combinator does not actually generate anything, it only influences further generation.
Customizing properties.
Use the Fuzz.For<T>().Customize<TProperty>(Expression<Func<T, TProperty>> func, Generator<TProperty>)
method chain.
F.i. :
Fuzz.For<SomeThingToGenerate>().Customize(s => s.MyProperty, Fuzz.Constant(42))
The property specified will be generated using the passed in generator.
An overload exists which allows for passing a value instead of a generator.
Derived classes generated also use the custom property.
*Note π The Customize combinator does not actually generate anything, it only influences further generation.
Customizing constructors.
Use the Fuzz.For<T>().Construct<TArg>(Expression<Func<T, TProperty>> func, Generator<TProperty>)
method chain.
F.i. :
Fuzz.For<SomeThing>().Construct(Fuzz.Constant(42))
Subsequent calls to Fuzz.One<T>()
will then use the registered constructor.
Various overloads exist :
Fuzz.For<T>().Construct<T1, T2>(Generator<T1> g1, Generator<T2> g2)
Fuzz.For<T>().Construct<T1, T2>(Generator<T1> g1, Generator<T2> g2, Generator<T3> g3)
Fuzz.For<T>().Construct<T1, T2>(Generator<T1> g1, Generator<T2> g2, Generator<T3> g3, Generator<T4> g4)
Fuzz.For<T>().Construct<T1, T2>(Generator<T1> g1, Generator<T2> g2, Generator<T3> g3, Generator<T4> g4, Generator<T5> g5)
After that, ... you're on your own.
Or use the factory method overload:
Fuzz.For<T>().Construct<T>(Func<T> ctor)
*Note π The Construct combinator does not actually generate anything, it only influences further generation.
Many objects.
Use The .Many(int number)
generator extension.
The generator will generate an IEnumerable<T> of int number
elements where T is the result type of the extended generator.
An overload exists (.Many(int min, int max
) where the number of elements is in between the specified arguments.
ToArray.
Use The .ToArray()
generator extension.
The Many
generator above returns an IEnumerable.
This means it's value would be regenerated if we were to iterate over it more than once.
Use ToArray
to fix the IEnumerable in place, so that it will return the same result with each iteration.
It can also be used to force evaluation in case the IEnumerable is not enumerated over because there's nothing in your select clause
referencing it.
Inheritance.
Use The Fuzz.For<T>().GenerateAsOneOf(params Type[] types)
method chain.
F.i. :
Fuzz.For<SomeThingAbstract>().GenerateAsOneOf(
typeof(SomethingDerived), typeof(SomethingElseDerived))
When generating an object of type T, an object of a random chosen type from the provided list will be generated instead.
**Note π* The GenerateAsOneOf(...)
combinator does not actually generate anything, it only influences further generation.
ToList.
Use The .ToList()
generator extension.
Similar to the ToArray
method. But instead of an Array, this one returns a, you guessed it, List.
Replacing Primitive Generators
Use the .Replace()
extension method.
Example
var generator =
from _ in Fuzz.Constant(42).Replace()
from result in Fuzz.One<SomeThingToGenerate>()
select result;
When executing above generator it will return a SomeThingToGenerate object where all integers have the value 42.
Replacing a primitive generator automatically impacts its nullable counterpart.
Replacing a nullable primitive generator does not impacts it's non-nullable counterpart.
Replacements can occur multiple times during one generation :
var generator =
from _ in Fuzz.Constant(42).Replace()
from result1 in Fuzz.One<SomeThingToGenerate>()
from __ in Fuzz.Constant(666).Replace()
from result2 in Fuzz.One<SomeThingToGenerate>()
select new[] { result1, result2 };
When executing above generator result1 will have all integers set to 42 and result2 to 666.
*Note π The Replace combinator does not actually generate anything, it only influences further generation.
Generating Hierarchies
Relations.
In the same way one can Customize
primitives, this can also be done for references.
E.g. :
var generator =
from product in Fuzz.One<ProductItem>()
from setProduct in Fuzz.For<OrderLine>().Customize(orderline => orderline.Product, product)
from orderline in Fuzz.One<OrderLine>()
select orderline;
In case of a one-to-many relation where the collection is inaccessible, but a method is provided for adding the many to the one,
we can use the Apply
method, which is explained in detail in the chapter 'Other Useful Generators'.
E.g. :
var generator =
from order in Fuzz.One<Order>()
from addLine in Fuzz.For<OrderLine>().Apply(order.AddOrderLine)
from lines in Fuzz.One<OrderLine>().Many(20).ToArray()
select order;
Note the ToArray
call on the orderlines.
This forces enumeration and is necessary because the lines are not enumerated over just by selecting the order.
If we were to select the lines instead of the order, ToArray
would not be necessary.
Relations defined by constructor injection can be generated using the One<T>(Func<T> constructor)
overload.
E.g. :
var generator =
from category in Fuzz.One<Category>()
from subCategory in Fuzz.One(() => new SubCategory(category)).Many(20)
select category;
Depth Control.
As mentioned in the A simple object section: βThe object properties will also be automatically filled in.β
However, this automatic population only applies to the first level of object properties.
Deeper properties will remain null unless configured otherwise.
So if we have the following class :
public class NoRecurse { }
public class Recurse
{
public Recurse Child { get; set; }
public NoRecurse OtherChild { get; set; }
public override string ToString()
{
var childString =
Child == null ? "<null>" : Child.ToString();
var otherChildString =
OtherChild == null ? "<null>" : "{ NoRecurse }";
return $"{{ Recurse: Child = {childString}, OtherChild = {otherChildString} }}";
}
}
If we then do :
Console.WriteLine(Fuzz.One<Recurse>().Generate().ToString());
It outputs :
{ Recurse: Child = <null>, OtherChild = { NoRecurse } }
While this may seem counter-intuitive, it is an intentional default to prevent infinite recursion or overly deep object trees.
Internally, a DepthConstraint(int Min, int Max)
is registered per type.
The default values are new(1, 1)
.
Revisiting our example we can see that both types have indeed been generated with these default values.
You can control generation depth per type using the .Depth(min, max)
combinator.
For instance:
var generator =
from _ in Fuzz.For<Recurse>().Depth(2, 2)
from recurse in Fuzz.One<Recurse>()
select recurse;
Console.WriteLine(generator.Generate().ToString());
Outputs:
{ Recurse: Child = { Recurse: Child = <null>, OtherChild = { NoRecurse } }
, OtherChild = { NoRecurse }
}
Recap:
Depth(1, 1)
{ Recurse: Child = <null>, OtherChild = { NoRecurse } }
Depth(2, 2)
{ Recurse:
Child = { Recurse: Child = <null>, OtherChild = { NoRecurse } },
OtherChild = { NoRecurse }
}
Depth(3, 3)
{ Recurse:
Child = { Recurse:
Child = { Recurse: Child = <null>, OtherChild = { NoRecurse } },
OtherChild = { NoRecurse } },
OtherChild = { NoRecurse }
}
Using for instance .Depth(1, 3)
allows the generator to randomly choose a depth between 1 and 3 (inclusive) for that type.
This means some instances will be shallow, while others may be more deeply nested, introducing variability within the defined bounds.
**Note π* The Depth(...)
combinator does not actually generate anything, it only influences further generation.
Trees.
Depth control together with the .GenerateAsOneOf(...)
combinator mentioned above and the previously unmentioned TreeLeaf<T>()
one allows you to build tree type hierarchies.
Given the canonical abstract Tree, concrete Branch and Leaf example model, we can generate this like so:
var generator =
from _d in Fuzz.For<Tree>().Depth(1, 3)
from _i in Fuzz.For<Tree>().GenerateAsOneOf(typeof(Branch), typeof(Leaf))
from _l in Fuzz.For<Tree>().TreeLeaf<Leaf>()
from tree in Fuzz.One<Tree>()
select tree;
Our leaf has an int value property, so the following:
Console.WriteLine(generator.Generate().ToString());
Would output something like:
Node(Leaf(31), Node(Leaf(71), Leaf(10)))
**Note π* The TreeLeaf<T>()
combinator does not actually generate anything, it only influences further generation.
Other Useful Generators
Apply.
Use the .Apply<T>(Func<T, T> func)
extension method.
Applies the specified Function to the generated value, returning the result.
F.i. Fuzz.Constant(41).Apply(i => i + 1)
will return 42.
Par example, when you want all decimals to be rounded to a certain precision :
var generator =
from _ in Fuzz.Decimal().Apply(d => Math.Round(d, 2)).Replace()
from result in Fuzz.One<SomeThingToGenerate>()
select result;
An overload exists with signature Apply<T>(Action<T> action)
.
This is useful when dealing with objects and you just don't want to return said object.
E.g. Fuzz.One<SomeThingToGenerate>().Apply(session.Save)
.
This function also exists as a convention instead of a generator.
E.g. Fuzz.For<SomeThingToGenerate>().Apply(session.Save)
.
In this case nothing is generated but instead the function will be applied to all objects of type T during generation.
There is no Fuzz.For<T>().Apply(Func<T, T> func)
as For can only be used for objects, so there is no need for it really.
Lastly the convention based Apply
has an overload which takes another generator.
This generator then provides a value which can be used in the action parameter.
E.g. :
var parents = ...
Fuzz.For<SomeChild>().Apply(Fuzz.ChooseFrom(parents), (child, parent) => parent.Add(child))
Picking an element out of a range.
Use Fuzz.ChooseFrom<T>(IEnumerable<T> values)
.
Picks a random value from a list of options.
F.i. Fuzz.ChooseFrom(new []{ 1, 2 })
will return either 1 or 2.
A helper method exists for ease of use when you want to pass in constant values as in the example above.
I.e. : Fuzz.ChooseFromThese(1, 2)
Another method provides a semi-safe way to pick from what might be an empty list.
I.e. : Fuzz.ChooseFromWithDefaultWhenEmpty(new List<int>())
, which returns the default, in this case zero.
You can also pick from a set of Generators.
I.e. : Fuzz.ChooseGenerator(Fuzz.Constant(1), Fuzz.Constant(2))
Generating unique values.
Use the .Unique(object key)
extension method.
Makes sure that every generated value is unique.
When asking for more unique values than the generator can supply, an exception is thrown.
Multiple unique generators can be defined in one 'composed' generator, without interfering with eachother by using a different key.
When using the same key for multiple unique generators all values across these generators are unique.
An overload exist taking a function as an argument allowing for a dynamic key.
Filtering generated values.
Use the .Where(Func<T, bool>)
extension method.
Makes sure that every generated value passes the supplied predicate.
Casting Generators.
Various extension methods allow for casting the generated value.
.AsString()
: Invokes.ToString()
on the generated value and casts the generator fromGenerator<T>
toGenerator<string>
. Useful f.i. to generate numeric strings..AsObject()
: Simply casts the generator itself fromGenerator<T>
toGenerator<object>
. Mostly used internally..Nullable()
: Casts aGenerator<T>
toGenerator<T?>
. In addition generates null 1 out of 5 times..Nullable(int timesBeforeResultIsNullAproximation)
: overload ofNullable()
, generates null 1 out oftimesBeforeResultIsNullAproximation
times .
How About Null(s)?
Various extension methods allow for influencing null generation.
.Nullable()
: Casts aGenerator<T>
toGenerator<T?>
. In addition generates null 1 out of 5 times.
Used for value types.
.Nullable(int timesBeforeResultIsNullAproximation)
: overload ofNullable()
, generates null 1 out oftimesBeforeResultIsNullAproximation
times ..NullableRef()
: Casts aGenerator<T>
toGenerator<T?>
. In addition generates null 1 out of 5 times.
Used for reference types, including
string
.
.NullableRef(int timesBeforeResultIsNullAproximation)
: overload ofNullableRef()
, generates null 1 out oftimesBeforeResultIsNullAproximation
times .
'Generating' constants.
Use Fuzz.Constant<T>(T value)
.
This generator is most useful in combination with others and is used to inject constants into combined generators.
'Never return null.
Use the .NeverReturnNull()
extension method.`.
Only available on generators that provide Nullable<T>
values, this one makes sure that, you guessed it, the nullable generator never returns null.
The Primitive Generators
Integers.
Use Fuzz.Int()
.
The overload Fuzz.Int(int min, int max)
generates an int higher or equal than min and lower than max.
Throws an ArgumentException if min > max.
The default generator is (min = 1, max = 100).
Can be made to return int?
using the .Nullable()
combinator.
int
is automatically detected and generated for object properties.Int32
is automatically detected and generated for object properties.int?
is automatically detected and generated for object properties.
Chars.
Use Fuzz.Char()
.
No overload exists.
The default generator always generates a char between lower case 'a' and lower case 'z'.
Can be made to return char?
using the .Nullable()
combinator.
char
is automatically detected and generated for object properties.char?
is automatically detected and generated for object properties.
Strings.
Use Fuzz.String()
.
The generator always generates every char element of the string to be between lower case 'a' and lower case 'z'.
The overload Fuzz.String(int min, int max)
generates an string of length higher or equal than min and lower than max.
The Default generator generates a string of length higher than 0 and lower than 10.
string
is automatically detected and generated for object properties.
Can be made to return string?
using the .NullableRef()
combinator.
Booleans.
Use Fuzz.Bool()
.
No overload exists.
The default generator generates True or False.
Can be made to return bool?
using the .Nullable()
combinator.
bool
is automatically detected and generated for object properties.bool?
is automatically detected and generated for object properties.
Decimals.
Use Fuzz.Decimal()
.
The overload Fuzz.Decimal(decimal min, decimal max)
generates a decimal higher or equal than min and lower than max.
Throws an ArgumentException if min > max.
The default generator is (min = 1, max = 100).
Can be made to return decimal?
using the .Nullable()
combinator.
decimal
is automatically detected and generated for object properties.decimal?
is automatically detected and generated for object properties.
DateTimes.
Use Fuzz.DateTime()
.
The overload Fuzz.DateTimes(DateTime min, DateTime max)
generates a DateTime higher or equal than min and lower than max.
The default generator is (min = new DateTime(1970, 1, 1), max = new DateTime(2020, 12, 31)).
Can be made to return DateTime?
using the .Nullable()
combinator.
DateTime
is automatically detected and generated for object properties.DateTime?
is automatically detected and generated for object properties.
Longs.
Use Fuzz.Long()
.
The overload Fuzz.Long(long min, long max)
generates a long higher or equal than min and lower than max.
Throws an ArgumentException if min > max.
The default generator is (min = 1, max = 100).
Can be made to return long?
using the .Nullable()
combinator.
long
is automatically detected and generated for object properties.Int64
is automatically detected and generated for object properties.long?
is automatically detected and generated for object properties.
Doubles.
Use Fuzz.Double()
.
The overload Fuzz.Double(double min, double max)
generates a double higher or equal than min and lower than max.
Throws an ArgumentException if min > max.
The default generator is (min = 1, max = 100).
Can be made to return double?
using the .Nullable()
combinator.
double
is automatically detected and generated for object properties.double?
is automatically detected and generated for object properties.
Floats.
Use Fuzz.Float()
.
The overload Fuzz.Float(float min, float max)
generates a float higher or equal than min and lower than max.
Throws an ArgumentException if min > max.
The default generator is (min = 1, max = 100).
Can be made to return float?
using the .Nullable()
combinator.
float
is automatically detected and generated for object properties.float?
is automatically detected and generated for object properties.
Guids.
Use Fuzz.Guid()
.
There is no overload.
The default generator never generates Guid.Empty.
Can be made to return Guid?
using the .Nullable()
combinator.
Guid
is automatically detected and generated for object properties.Guid?
is automatically detected and generated for object properties.
Shorts.
Use Fuzz.Short()
.
The overload Fuzz.Short(short min, short max)
generates a short higher or equal than min and lower than max.
The default generator is (min = 1, max = 100).
Can be made to return short?
using the .Nullable()
combinator.
short
is automatically detected and generated for object properties.short?
is automatically detected and generated for object properties.
TimeSpans.
Use Fuzz.TimeSpan()
.
The overload Fuzz.TimeSpan(int max)
generates a TimeSpan with Ticks higher or equal than 1 and lower than max.
The default generator is (max = 1000).
Can be made to return TimeSpan?
using the .Nullable()
combinator.
TimeSpan
is automatically detected and generated for object properties.TimeSpan?
is automatically detected and generated for object properties.
Enums.
Use Fuzz.Enum<T>()
, where T is the type of Enum you want to generate.
No overload exists.
The default generator just picks a random value from all enemeration values.
An Enumeration is automatically detected and generated for object properties.
A nullable Enumeration is automatically detected and generated for object properties.
Passing in a non Enum type for T throws an ArgumentException.
Creating Custom Generators
How To
Any function that returns a value of type Generator<T>
can be used as a generator.
Generator is defined as a delegate like so :
public delegate IResult<TValue> Generator<out TValue>(State input)
So f.i. to define a generator that always returns the number forty-two we need a function that returns the following :
return s => new Result<State, int>(42, s);
As you can see from the signature a state object is passed to the generator. This is where the random seed lives. If you want any kind of random, it is advised to use that one, like so :
return s => new Result<State, int>(s.Random.Next(42, 42), s);
See also : Creating a counter generator.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- No dependencies.
NuGet packages (1)
Showing the top 1 NuGet packages that depend on QuickFuzzr:
Package | Downloads |
---|---|
QuickAcid
Drop it in acid. Look for gold. Like alchemy, but reproducible. |
GitHub repositories
This package is not used by any popular GitHub repositories.