Releases: DyegoMaas/ForeverFactory
New Feature: Callbacks
Callbacks
Now it is possible to define a callback with the new Do()
method. It works essencially just like the With()
method, but with a different signature.
var project = MagicFactory.For<Project>()
.With(x => x.ProjectName = "Apollo")
.Do(x => Console.WriteLine(x.ProjectName) // prints "Apollo"
.Build();
New feature: Global settings
Features
Global Settings
Added option to configure a default behavior globally in a project:
ForeverFactoryGlobalSettings
.UseBehavior(new FillWithSequentialValuesBehavior(options =>
{
options.DateTimeOptions = new DateTimeSequenceOptions
{
DateTimeIncrements = DateTimeIncrements.Hours,
StartDate = 2.September(2020)
};
options.FillNullables = false;
options.Recursive = false;
}));
var instances = MagicFactory.For<ClassA>().Many(2).Build().ToArray();
var secondInstance = instances[1];
secondInstance.DateTimeProperty.Should().Be(2.September(2020).At(1.Hours()));
secondInstance.NullableDateTimeProperty.Should().BeNull("FillNullables option is set to false");
secondInstance.B.Should().BeNull("Recursive option is set to false");
v4.3.0 - New features and fixes
Features
This release adds some new features and improves utility for common usage scenarios.
DateTimes are now supported in FillWithEmptyValuesBehavior
DateTimes properties will be set to 1753/1/1. This value can be configured through the new option StartDate.
DateTimes are now supported in FillWithSequentialValuesBehavior
DateTimes properties will be set to 1753/1/1. This value can be configured through the new option StartDate.
By default, dates will be increment on a day-by-day basis. The increments can be configured through the new option DateTimeIncrements to one of these:
- Days
- Months
- Years
- Hours
- Minutes
- Seconds
- Milliseconds
- Ticks
Example configuration
var behavior = new FillWithSequentialValuesBehavior(options =>
{
options.DateTimeOptions = new DateTimeSequenceOptions
{
StartDate = new Date(1995, 2, 1),
DateTimeIncrements = DateTimeIncrements.Days
};
});
var customers = MagicFactory.For<Customer>()
.WithBehavior(behavior)
.Many(3)
.Build()
.ToList();
customers[0].Birthday.Should().Be(1.February(1995));
customers[1].Birthday.Should().Be(2.February(1995));
customers[2].Birthday.Should().Be(3.February(1995));
Adds support to filling nullable fields and properties
Previously, nullable properties and fields were ignored. Now they are filled by default, in addition to normal fields and properties:
public class Class {
public string? NullableStringProperty { get; set; }
public byte? NullableByteProperty { get; set; }
public short? NullableShortProperty { get; set; }
public ushort? NullableUShortProperty { get; set; }
public int? NullableIntProperty { get; set; }
public uint? NullableUIntProperty { get; set; }
public long? NullableLongProperty { get; set; }
public ulong? NullableULongProperty { get; set; }
public float? NullableFloatProperty { get; set; }
public double? NullableDoubleProperty { get; set; }
public decimal? NullableDecimalProperty { get; set; }
public DateTime? NullableDateTimeProperty { get; set; }
}
This will be applied to both FillWithEmptyValuesBehavior
and FillWithSequentialValuesBehavior
.
There is also a new option that allows disabling filling Nullable fields. This option can be useful to preserve the previous behavior.
new FillWithEmptyValuesBehavior(options => options.FillNullables = false)
Fixes virtual call from constructor
The method Customize(ICustomizeFactoryOptions<T> customization)
, implemented by customized factories that extend MagicFactory, was previously called from the constructor of MagicFactory
.
This means the following setup would not work, because the Customize() method would be invoked before the constructor of the PersonFactory
class finished execution:
new PersonFactory : MagicFactory<Person>
{
private readonly int _age;
public CustomFactory(int age) {
_age = age;
}
protected override void Customize(ICustomizeFactoryOptions<Person> customization)
{
customization.Set(x => x.Age = _age);
}
}
New Feature - filling public fields
Features
- Added support to filling public fields, in the addition to public properties, that were already supported.
Previous behavior:
private class ClassA
{
public string PublicProperty { get; set; } // was already setting
public string PublicField; // would remain null
}
This was true for all behaviors that depend on recursive traversal:
- FillWithEmptyValuesBehavior
- FillWithSequentialValuesBehavior
New behavior
private class ClassA
{
public string PublicProperty { get; set; } // was already setting
public string PublicField; // will set value as expected
}
New behavior FillWithSequentialValuesBehavior
Features
This PR brings a new Behavior, FillWithSequentialValuesBehavior
, which can initialize properties values that are sequential, according to their types.
This is especially useful when initializing collections. This behavior may be made default in version 5.
Example
The example below shows how to enable this behavior.
var people = MagicFactory
.For<ClassWithInteger>()
.WithBehavior(new FillWithSequentialValuesBehavior())
.Many(100)
.Build();
people[0].Name.Should().Be("Name1");
people[0].Age.Should().Be(1);
people[0].Address.ZipCode.Should().Be("ZipCode1");
people[1].Name.Should().Be("Name2");
people[1].Age.Should().Be(2);
people[1].Address.ZipCode.Should().Be("ZipCode2");
public class Customer
{
public string Name { get; set; }
public int Age { get; set; }
public Address Address { get; set; }
}
public class Address
{
public string ZipCode { get; set; }
}
Options
The behavior also supports disabling recursion.
var people = MagicFactory
.For<ClassWithInteger>()
.WithBehavior(new FillWithSequentialValuesBehavior(options => options.Recursive = false))
.Many(100)
.Build();
people[0].Name.Should().Be("Name1");
people[0].Address.Should().BeNull();
people[1].Name.Should().Be("Name2");
people[1].Address.Should().BeNull();
Making Nuget packages deterministic
Features
Changed release workflow in order to force deterministic builds for new published packages.
Rebuilt fluent interfaces
v4.0.0
Features
It is now possible to explicitly state the only one instance is being built by using the new One()
method:
var product = MagicFactory.For<Product>()
.One().With(x => x.Description = "Nimbus 2000")
.Build();
Also, fluent interfaces that control the flow of configurations were restructured. As a result, some previously possible paths were removed. These paths are:
MagicFactory.For<Product>().PlusOne()
//and
MagicFactory.For<Product>().Plus(2)
These paths were not actually meaningful, and so they were removed. Unfortunately, this change breaks compatibility in some edge cases and forces a major version bump. It is not expected to affect users, though.
Fixes
- Reintroduced range validation for the
.WithFirst(n)
method, which was lost in the v2.0.0 rewrite - Reintroduced range validation for the
.WithLast(n)
method, which was lost in the v2.0.0 rewrite
Added concept of Behaviors
v3.0.0
These release breaks compatibility with version 2.0 regarding how factories that extend MagicFactory<T>
customize its behavior. Prior to the new changes, these configurations were made in the factory's constructor. This was changed, and now it is done through the Customize
method, as in the example below:
protected override void Customize(ICustomizeFactoryOptions<Product> customization)
{
// customizations done through the customization parameter
}
Features
- ForeverFactory now allows to customize how objects will be initialized, before any further customization;
- DoNotFillBehavior is now the default behavior, and behaves exactly like versions 2.0 and below;
- FillWithEmptyValuesBehavior was added, which recursively initializes all properties.
Fixes
- Fixed a bug which caused configurations made with method
Set()
in a customized factory to be lost when the factory was used with theMany()
method.
Reenabled flow MagicFactory.For<T>.Many()
Features
- Reenabled flow MagicFactory.For.Many(), that was obfuscated in the rewrite.
Major rewrite
ForeverFactory 2.0 is backward compatible with version 1.1.
Features
New core:
- More readable code;
- More testable contracts.