Skip to content

Commit

Permalink
Allow Fixture customization (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
victorsebrito committed Apr 14, 2022
1 parent 9b8d55e commit 1d9a4c9
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 29 deletions.
44 changes: 31 additions & 13 deletions Source/SweetBuilders/BuilderBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,35 @@ public abstract class BuilderBase<TObject, TBuilder>
/// <summary>
/// Initializes a new instance of the <see cref="BuilderBase{TObject, TBuilder}"/> class.
/// </summary>
protected BuilderBase() => this.Composer = this.Fixture.Build<TObject>()
.FromFactory(Factories.Default<TObject>);
protected BuilderBase()
: this(CreateComposer())
{
}

/// <summary>
/// Initializes a new instance of the <see cref="BuilderBase{TObject, TBuilder}"/> class.
/// </summary>
/// <param name="factory">A factory of the <typeparamref name="TObject"/> class.</param>
/// <param name="factory">A factory of <typeparamref name="TObject"/>.</param>
protected BuilderBase(Func<TObject> factory)
: this(CreateComposer().FromFactory(factory))
{
if (factory == null)
{
throw new ArgumentNullException(nameof(factory));
}

var customizationComposer = this.Fixture.Build<TObject>();
this.Composer = customizationComposer.FromFactory(factory);
}

private Fixture Fixture { get; } = new Fixture
/// <summary>
/// Initializes a new instance of the <see cref="BuilderBase{TObject, TBuilder}"/> class.
/// </summary>
/// <param name="fixture">The fixture that will be used to initialize the builder.</param>
protected BuilderBase(Fixture fixture)
: this(CreateComposer(fixture))
{
OmitAutoProperties = true,
};
}

/// <summary>
/// Initializes a new instance of the <see cref="BuilderBase{TObject, TBuilder}"/> class.
/// </summary>
/// <param name="composer">The composer that will be used by the builder.</param>
protected BuilderBase(IPostprocessComposer<TObject>? composer = null)
=> this.Composer = composer ?? CreateComposer();

private IPostprocessComposer<TObject> Composer { get; set; }

Expand Down Expand Up @@ -285,4 +292,15 @@ public TBuilder Without<TProperty>(Expression<Func<TObject, TProperty>> property
/// <param name="count">The number of objects to create.</param>
/// <returns>A sequence of anonymous objects of type <typeparamref name="TObject"/>.</returns>
public IEnumerable<TObject> CreateMany(int count) => this.Composer.CreateMany(count);

private static Fixture CreateFixture() => new()
{
OmitAutoProperties = true,
};

private static ICustomizationComposer<TObject> CreateComposer(Fixture? fixture = null)
{
fixture ??= CreateFixture();
return fixture.Build<TObject>();
}
}
25 changes: 14 additions & 11 deletions Tests/SweetBuilders.Test/BuilderBaseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -268,30 +268,33 @@ public void ShouldCreateNInstancies()
}

[Fact]
public void ShouldThrowIfFactoryIsNull()
public void ShouldThrowIfPropertyNameIsNull()
{
var act = () => new FooBarInvalidBuilder();
var builder = Builder<Foo>.New;

#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
var act = () => builder.WithPrivate(null, string.Empty);
#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type.

using (new AssertionScope())
{
act.Should().Throw<ArgumentNullException>()
.WithParameterName("factory");
.WithParameterName("propertyName");
}
}

[Fact]
public void ShouldThrowIfPropertyNameIsNull()
public void ShouldRespectFixtureCustomizations()
{
var builder = Builder<Foo>.New;

#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
var act = () => builder.WithPrivate(null, string.Empty);
#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type.
var foo = new FooBuilderCustomFixture()
.Create();

using (new AssertionScope())
{
act.Should().Throw<ArgumentNullException>()
.WithParameterName("propertyName");
foo.Bar.Should().NotBeNull("the builder should generate all public properties");
foo.Bar?.Name.Should().Be(
FooBuilderCustomFixture.NAME,
"the builder should respect any Fixture customizations");
}
}

Expand Down
21 changes: 16 additions & 5 deletions Tests/SweetBuilders.Test/FooBar.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace SweetBuilders.Test;

using System;
using AutoFixture;

#pragma warning disable CS0169, IDE0051 // Remove unused private members
#pragma warning disable SA1649 // File name should match first type name
Expand Down Expand Up @@ -53,14 +54,24 @@ internal class BarBuilder : BuilderBase<Bar, BarBuilder>
public BarBuilder() => this.With(x => x.Name, NAME);
}

internal class FooBarInvalidBuilder : BuilderBase<Foo, FooBarInvalidBuilder>
internal class FooBuilderCustomFixture : BuilderBase<Foo, FooBuilderCustomFixture>
{
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
public FooBarInvalidBuilder()
: base(null)
internal static readonly string NAME = Guid.NewGuid().ToString();

public FooBuilderCustomFixture()
: base(CreateFixture())
{
}

private static Fixture CreateFixture()
{
var fixture = new Fixture
{
OmitAutoProperties = false,
};
fixture.Customize<Bar>(bar => bar.With(x => x.Name, NAME));
return fixture;
}
#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type.
}
#pragma warning restore CS0169, IDE0051 // Remove unused private members
#pragma warning restore SA1649 // File name should match first type name
Expand Down

0 comments on commit 1d9a4c9

Please sign in to comment.