Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions BREAKING_CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ If you want to fix a static value for a property then by all means you can still
Version 2.0.0
-------------

The way that lists are generated no longer uses NBuilder - the new syntax is backwards compatible with NBuilder except that the namespace you need to include is different. You can also refactor your list generation to be a lot more terse, but that is optional. Any `BuildList` extension methods you created will now need to be deleted since they are no longer needed.
The way that lists are generated no longer uses NBuilder - the new syntax is backwards compatible with NBuilder except that the namespace you need to include is different. You can also refactor your list generation to be a lot more terse, but that is optional. Any `BuildList` extension methods you created will now need to be deleted since they are no longer needed. You also need to ensure that all of the methods you call are marked virtual so the list generation can proxy those method calls.

### Reason
In order to support a new, much terser syntax for generating lists we rewrote the list generation code ourselves. You can now do this:
Expand All @@ -44,7 +44,7 @@ You also no longer need a custom extension method for the `BuildList` method so

### Fix

Simply add the following to the files that generate lists of builders and the existing syntax should work:
Simply add the following to the files that generate lists of builders and change your builder modification methods to be virtual and the existing syntax should work:

```
using NTestDataBuilder.Lists;
Expand Down
12 changes: 12 additions & 0 deletions NTestDataBuilder.Tests/BuildListTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,17 @@ public void GivenListOfBuildersWithARangeOfCustomisationMethods_WhenBuildingEnti
customers[4].LastName.ShouldBe("Last Last");
customers.ShouldAllBe(c => c.YearJoined == 1999);
}

[Fact]
public void WhenBuildingEntities_ThenTheAnonymousValueFixtureIsSharedAcrossBuilders()
{
var customers = CustomerBuilder.CreateListOfSize(5).BuildList();

customers[0].CustomerClass.ShouldBe(CustomerClass.Normal);
customers[1].CustomerClass.ShouldBe(CustomerClass.Bronze);
customers[2].CustomerClass.ShouldBe(CustomerClass.Silver);
customers[3].CustomerClass.ShouldBe(CustomerClass.Gold);
customers[4].CustomerClass.ShouldBe(CustomerClass.Platinum);
}
}
}
2 changes: 1 addition & 1 deletion NTestDataBuilder.Tests/Builders/BasicCustomerBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public class BasicCustomerBuilder : TestDataBuilder<Customer, BasicCustomerBuild
{
protected override Customer BuildObject()
{
return new Customer("First Name", "Last Name", 2013);
return new Customer("customer1", "First Name", "Last Name", 2013, CustomerClass.Normal);
}

public new BasicCustomerBuilder Set<TValue>(Expression<Func<Customer, TValue>> property, TValue value)
Expand Down
4 changes: 3 additions & 1 deletion NTestDataBuilder.Tests/Builders/CustomerBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ public virtual CustomerBuilder WhoJoinedIn(int yearJoined)
protected override Customer BuildObject()
{
return new Customer(
Get(x => x.Identifier),
Get(x => x.FirstName),
Get(x => x.LastName),
Get(x => x.YearJoined)
Get(x => x.YearJoined),
Get(x => x.CustomerClass)
);
}
}
Expand Down
8 changes: 7 additions & 1 deletion NTestDataBuilder.Tests/Entities/Customer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,20 @@ public class Customer
{
protected Customer() {}

public Customer(string firstName, string lastName, int yearJoined)
public Customer(string identifier, string firstName, string lastName, int yearJoined, CustomerClass customerClass)
{
if (string.IsNullOrEmpty(identifier))
throw new ArgumentNullException("identifier");
if (string.IsNullOrEmpty(firstName))
throw new ArgumentNullException("firstName");
if (string.IsNullOrEmpty(lastName))
throw new ArgumentNullException("lastName");

Identifier = identifier;
FirstName = firstName;
LastName = lastName;
YearJoined = yearJoined;
CustomerClass = customerClass;
}

public virtual int CustomerForHowManyYears(DateTime since)
Expand All @@ -25,8 +29,10 @@ public virtual int CustomerForHowManyYears(DateTime since)
return since.Year - YearJoined;
}

public virtual string Identifier { get; private set; }
public virtual string FirstName { get; private set; }
public virtual string LastName { get; private set; }
public virtual int YearJoined { get; private set; }
public virtual CustomerClass CustomerClass { get; private set; }
}
}
11 changes: 11 additions & 0 deletions NTestDataBuilder.Tests/Entities/CustomerClass.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace NTestDataBuilder.Tests.Entities
{
public enum CustomerClass
{
Normal,
Bronze,
Silver,
Gold,
Platinum
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using NTestDataBuilder.EquivalenceClasses;
using Shouldly;
using Xunit;

namespace NTestDataBuilder.Tests.EquivalenceClasses
{
public class EnumEquivalenceClassesTests
{
public AnonymousValueFixture Any { get; private set; }

public EnumEquivalenceClassesTests()
{
Any = new AnonymousValueFixture();
}

[Fact]
public void WhenGettingAnyOfEnum_ThenReturnSequentialEnumValueEveryTimeUntilItWrapsAroundAgain()
{
var values = new[]
{
Any.Of<TestEnum>(),
Any.Of<TestEnum>(),
Any.Of<TestEnum>(),
Any.Of<TestEnum>(),
Any.Of<TestEnum>()
};

values.ShouldBe(new []{TestEnum.One, TestEnum.Two, TestEnum.Three, TestEnum.Four, TestEnum.One});
}

[Fact]
public void WhenGettingAnyEnumExceptOneValue_ThenReturnSequentialEnumValueExceptTheExceptionEveryTimeUntilItWrapsAroundAgain()
{
var values = new[]
{
Any.Except(TestEnum.Two),
Any.Except(TestEnum.Two),
Any.Except(TestEnum.Two),
Any.Except(TestEnum.Two)
};

values.ShouldBe(new[] { TestEnum.One, TestEnum.Three, TestEnum.Four, TestEnum.One });
}
}

enum TestEnum
{
One,
Two,
Three,
Four
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@

namespace NTestDataBuilder.Tests.EquivalenceClasses
{
public class DictionaryEquivalenceClassesTests
public class PersonEquivalenceClassesTests
{
public static AnonymousValueFixture Any { get; private set; }

public DictionaryEquivalenceClassesTests()
public PersonEquivalenceClassesTests()
{
Any = new AnonymousValueFixture();
}
Expand Down
23 changes: 21 additions & 2 deletions NTestDataBuilder.Tests/GetAnonymousTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using NTestDataBuilder.Lists;
using NTestDataBuilder.DataSources.Person;
using NTestDataBuilder.Lists;
using NTestDataBuilder.Tests.Builders;
using NTestDataBuilder.Tests.TestHelpers;
using Shouldly;
Expand Down Expand Up @@ -48,10 +49,28 @@ public void GivenNoValueHasBeenSetForAPropertyAndAGlobalSupplierHasBeenRegistere
_b.Get(x => x.FirstName).ShouldBe(globalVal);
}

[Fact]
public void GivenNoValueHasBeenSetForAPropertyNamedFirstName_WhenRetrievingTheValueForTheProperty_ThenReturnAFirstName()
{
var firstName = _b.Get(x => x.FirstName);

new PersonNameFirstSource().Data
.ShouldContain(firstName);
}

[Fact]
public void GivenNoValueHasBeenSetForAPropertyNamedLastName_WhenRetrievingTheValueForTheProperty_ThenReturnALastName()
{
var lastName = _b.Get(x => x.LastName);

new PersonNameLastSource().Data
.ShouldContain(lastName);
}

[Fact]
public void GivenNoValueHasBeenSetForAStringProperty_WhenRetrievingTheValueForThatProperty_ThenReturnPropertyNameFollowedByGuid()
{
_b.Get(x => x.FirstName).ShouldMatch("^FirstName[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}$");
_b.Get(x => x.Identifier).ShouldMatch("^Identifier[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}$");
}

[Fact]
Expand Down
4 changes: 3 additions & 1 deletion NTestDataBuilder.Tests/NTestDataBuilder.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Entities\CustomerClass.cs" />
<Compile Include="DataSources\DataSourceTests.cs" />
<Compile Include="DataSources\Dictionaries\CacheTests.cs" />
<Compile Include="DataSources\Dictionaries\FileDictionaryRepositoryIntegrationTests.cs" />
Expand All @@ -57,8 +58,9 @@
<Compile Include="DataSources\Generators\RandomGeneratorTests.cs" />
<Compile Include="DataSources\Generators\SequentiaGeneratorTests.cs" />
<Compile Include="DataSources\DataSourceConventionTests.cs" />
<Compile Include="EquivalenceClasses\DictionaryEquivalenceClassesTests.cs" />
<Compile Include="EquivalenceClasses\PersonEquivalenceClassesTests.cs" />
<Compile Include="EquivalenceClasses\IntegerEquivalenceClassesTests.cs" />
<Compile Include="EquivalenceClasses\EnumEquivalenceClassesTests.cs" />
<Compile Include="EquivalenceClasses\StringEquivalenceClassesTests.cs" />
<Compile Include="AsProxyTests.cs" />
<Compile Include="BuildListTests.cs" />
Expand Down
2 changes: 2 additions & 0 deletions NTestDataBuilder/AnonymousValueFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ static AnonymousValueFixture()
GlobalValueSuppliers = new List<IAnonymousValueSupplier>();
DefaultValueSuppliers = new IAnonymousValueSupplier[]
{
new DefaultFirstNameValueSupplier(),
new DefaultLastNameValueSupplier(),
new DefaultStringValueSupplier(),
new DefaultValueTypeValueSupplier(),
new DefaultValueSupplier()
Expand Down
1 change: 1 addition & 0 deletions NTestDataBuilder/DataSources/Generators/RandomGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public RandomGenerator(int startIndex, int listSize)
_random = new Random();
}

/// <inerhitdoc />
public int Generate()
{
return _random.Next(StartIndex, ListSize);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public SequentialGenerator(int startIndex, int listSize, bool listShouldBeUnique
_currentListIndex = startIndex - 1;
}

/// <inerhitdoc />
public int Generate()
{
_currentListIndex++;
Expand Down
16 changes: 16 additions & 0 deletions NTestDataBuilder/DataSources/IDataSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,26 @@

namespace NTestDataBuilder.DataSources
{
/// <summary>
/// Provides data.
/// </summary>
/// <typeparam name="T">The type of data that is provided</typeparam>
public interface IDataSource<T>
{
/// <summary>
/// The underlying source of data.
/// </summary>
IList<T> Data { get; }

/// <summary>
/// The generator that is being used to return the data.
/// </summary>
IGenerator Generator { get; }

/// <summary>
/// Retrieve the next data value.
/// </summary>
/// <returns>The data value</returns>
T Next();
}
}
1 change: 1 addition & 0 deletions NTestDataBuilder/DummyContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace NTestDataBuilder
/// </summary>
public class DummyContext : ISpecimenContext
{
/// <inerhitdoc />
public object Resolve(object request)
{
return null;
Expand Down
39 changes: 39 additions & 0 deletions NTestDataBuilder/EquivalenceClasses/EnumEquivalenceClasses.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System;
using System.Linq;
using Ploeh.AutoFixture;

namespace NTestDataBuilder.EquivalenceClasses
{
/// <summary>
/// Extension methods that describe equivalence classes for generating anonymous enum values.
/// </summary>
public static class EnumEquivalenceClasses
{
/// <summary>
/// Generate and return an enum from any available values in the enum.
/// </summary>
/// <param name="fixture">The fixture to generate an enum for</param>
/// <returns>The generated enum</returns>
public static TEnum Of<TEnum>(this AnonymousValueFixture fixture)
where TEnum : struct, IComparable, IFormattable, IConvertible
{
return fixture.Fixture.Create<TEnum>();
}

/// <summary>
/// Generate and return an enum from any values in the enum except the provided exceptions.
/// </summary>
/// <param name="fixture">The fixture to generate an enum for</param>
/// <param name="except">A list of exceptions; recommend you specify by label for readability</param>
/// <returns>The generated enum</returns>
public static TEnum Except<TEnum>(this AnonymousValueFixture fixture, params TEnum[] except)
where TEnum : struct, IComparable, IFormattable, IConvertible
{
var value = fixture.Fixture.Create<TEnum>();
while (except.Contains(value))
value = fixture.Fixture.Create<TEnum>();

return value;
}
}
}
2 changes: 1 addition & 1 deletion NTestDataBuilder/Lists/EnsureAllMethodsVirtual.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public void MethodsInspected()

public void NonProxyableMemberNotification(Type type, MemberInfo memberInfo)
{
if (new[]{"get_Any", "Build", "AsProxy", "Get", "GetOrDefault", "Set", "Has", "get_ListBuilder", "set_ListBuilder"}.Contains(memberInfo.Name))
if (new[]{"get_Any", "set_Any", "Build", "AsProxy", "Get", "GetOrDefault", "Set", "Has", "get_ListBuilder", "set_ListBuilder"}.Contains(memberInfo.Name))
return;
throw new InvalidOperationException(string.Format("Tried to build a list with a builder who has non-virtual method. Please make {0} on type {1} virtual.", memberInfo.Name, type.Name));
}
Expand Down
3 changes: 2 additions & 1 deletion NTestDataBuilder/Lists/ListBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ internal ListBuilder(int size)
.CreateClassProxy(typeof (TBuilder), new ProxyGenerationOptions(new EnsureAllMethodsVirtual()), new ListBuilderInterceptor<TObject, TBuilder>(this));
BuilderProxy.ListBuilder = this;
_list = new List<TBuilder>();
var fixture = new AnonymousValueFixture();
for (var i = 0; i < size; i++)
_list.Add(new TBuilder());
_list.Add(new TBuilder {Any = fixture});
}

internal TBuilder BuilderProxy { get; private set; }
Expand Down
3 changes: 3 additions & 0 deletions NTestDataBuilder/NTestDataBuilder.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
<Compile Include="DataSources\Person\PersonNameSuffixSource.cs" />
<Compile Include="DataSources\Person\PersonNameTitleSource.cs" />
<Compile Include="DummyContext.cs" />
<Compile Include="EquivalenceClasses\EnumEquivalenceClasses.cs" />
<Compile Include="EquivalenceClasses\GeographyEquivalenceClassescs.cs" />
<Compile Include="EquivalenceClasses\IntegerEquivalenceClasses.cs" />
<Compile Include="EquivalenceClasses\PersonEquivalenceClasses.cs" />
Expand All @@ -86,6 +87,8 @@
<Compile Include="Lists\ListBuilderGenerator.cs" />
<Compile Include="Lists\ListBuilderInterceptor.cs" />
<Compile Include="PropertyNameGetter.cs" />
<Compile Include="Suppliers\DefaultLastNameValueSupplier.cs" />
<Compile Include="Suppliers\DefaultFirstNameValueSupplier.cs" />
<Compile Include="Suppliers\DefaultValueSupplier.cs" />
<Compile Include="Suppliers\DefaultStringValueSupplier.cs" />
<Compile Include="Suppliers\DefaultValueTypeValueSupplier.cs" />
Expand Down
22 changes: 22 additions & 0 deletions NTestDataBuilder/Suppliers/DefaultFirstNameValueSupplier.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using NTestDataBuilder.EquivalenceClasses;

namespace NTestDataBuilder.Suppliers
{
/// <summary>
/// Supplies default anonymous value for first names.
/// </summary>
public class DefaultFirstNameValueSupplier : IAnonymousValueSupplier
{
/// <inheritdoc />
public bool CanSupplyValue<TObject, TValue>(string propertyName)
{
return typeof (TValue) == typeof(string) && propertyName.ToLower() == "firstname";
}

/// <inheritdoc />
public TValue GenerateAnonymousValue<TObject, TValue>(AnonymousValueFixture any, string propertyName)
{
return (TValue) (object) any.PersonNameFirst();
}
}
}
Loading