The behavior you describe is intended by design. The .Build<T>()
customization creates a one-time-use customization that ignores all previously assigned customizations.
If the intention was to just create an instance using a previously applied type customization, then all you need to do is remove the .Build<T>()
statement from you test and just use .Create()
directly. This will avoid creating the customization from scratch.
var fixture = new Fixture();
fixture.Customize(new Conventions());
var entity = fixture.Create<MyObject>();
Since you are using EntityFramework it is likely that your navigation properties are marked as virtual
. You could write a IRequestSpecification
that would identify virtual members and use the Omitter
to omit all navigation properties.
Another approach to tackle your issue would be to consider changing the design of your domain models. Ask yourself whether it is a valid operation to allow clients of your domain model to "set/replace" the collection of boats for example. If the answer is "no" you might want to change the model so that this rule is reflected in the design itself, i.e. make the setter private and change the collection to a read only collection. If you do this AutoFixture will ignore the navigation properties and you would be able to set their values using the appropriate business rules.
Finally if you still want to reuse a parts of the customization you could extend AutoFixture in a way that would allow this kind of operation. Both Customize<T>()
and Build<T>()
are employing the IPostprocessComposer<T>
interface to compose the inline customizations. You could write an extension method that intervenes in the process and delegates the customization to a third party.
public static class ComposerExtensions
{
public static IPostprocessComposer<T> Using<T>(this IPostprocessComposer<T> source, IPartialPostprocessComposer<T> composer)
{
return composer.Compose(source);
}
}
Now assuming a third party could look like this.
public class MyClassPartialComposer : IPartialPostprocessComposer<MyClass>
{
public IPostprocessComposer<MyClass> Compose(IPostprocessComposer<MyClass> source)
{
return source
.Without(x => x.Cars)
.Without(x => x.Boats);
}
}
Your customization could look like this.
var actual = fixture.Build<MyClass>()
.Using(new MyClassPartialComposer())
.With(x => x.Name, "hello")
.Create();
With this approach you could also compose parts of the inline customization.
Remember though that this last approach is not supported officially by AutoFixture and you'd have to define the extension method and the partial composer implementations yourself.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…