From 205c61ecfd086b518751cc96e8e079d32fb6deba Mon Sep 17 00:00:00 2001 From: Michael Whelan Date: Sun, 26 Apr 2015 10:19:48 +0100 Subject: [PATCH 01/10] Added a static Builder class to emulate NBuilder behaviour --- .../BuilderBuildListTests.cs | 194 ++++++++++++++++++ TestStack.Dossier.Tests/BuilderBuildTests.cs | 56 +++++ TestStack.Dossier.Tests/GetAnonymousTests.cs | 14 +- .../StaticAnonymousValueSupplier.cs | 14 +- .../TestStack.Dossier.Tests.csproj | 2 + TestStack.Dossier/AnonymousValueFixture.cs | 10 + TestStack.Dossier/Builder.cs | 13 ++ TestStack.Dossier/IAnonymousValueSupplier.cs | 22 +- TestStack.Dossier/PropertyNameGetter.cs | 26 +++ .../Suppliers/DefaultEmailValueSupplier.cs | 17 +- .../DefaultFirstNameValueSupplier.cs | 17 +- .../Suppliers/DefaultLastNameValueSupplier.cs | 18 +- .../Suppliers/DefaultStringValueSupplier.cs | 15 +- .../Suppliers/DefaultValueSupplier.cs | 21 +- .../DefaultValueTypeValueSupplier.cs | 21 +- TestStack.Dossier/TestDataBuilder.cs | 38 +++- TestStack.Dossier/TestStack.Dossier.csproj | 1 + 17 files changed, 483 insertions(+), 16 deletions(-) create mode 100644 TestStack.Dossier.Tests/BuilderBuildListTests.cs create mode 100644 TestStack.Dossier.Tests/BuilderBuildTests.cs create mode 100644 TestStack.Dossier/Builder.cs diff --git a/TestStack.Dossier.Tests/BuilderBuildListTests.cs b/TestStack.Dossier.Tests/BuilderBuildListTests.cs new file mode 100644 index 0000000..658815e --- /dev/null +++ b/TestStack.Dossier.Tests/BuilderBuildListTests.cs @@ -0,0 +1,194 @@ +using System.Collections.Generic; +using System.Linq; +using Shouldly; +using TestStack.Dossier.DataSources.Generators; +using TestStack.Dossier.Lists; +using TestStack.Dossier.Tests.Builders; +using TestStack.Dossier.Tests.Entities; +using Xunit; + +namespace TestStack.Dossier.Tests +{ + public class BuilderBuildListTests + { + [Fact] + public void GivenANormalBuilderInstance_WhenCallingIsListBuilderProxy_ThenReturnFalse() + { + var builder = Builder.CreateNew(); + + builder.IsListBuilderProxy().ShouldBe(false); + } + + [Fact] + public void GivenAListBuilderProxyInstance_WhenCallingIsListBuilderProxy_ThenReturnTrue() + { + var builder = Builder.CreateListOfSize(1).TheFirst(1); + + builder.IsListBuilderProxy().ShouldBe(true); + } + + [Fact] + public void GivenListOfBuilders_WhenCallingBuildListExplicitly_ThenAListOfEntitiesOfTheRightSizeShouldBeReturned() + { + var builders = Builder.CreateListOfSize(5); + + var entities = builders.BuildList(); + + entities.Count.ShouldBe(5); + } + + [Fact] + public void GivenListOfBuilders_WhenCallingBuildListImplicitly_ThenAListOfEntitiesOfTheRightSizeShouldBeReturned() + { + List entities = Builder.CreateListOfSize(5); + + entities.Count.ShouldBe(5); + } + + [Fact] + public void GivenListOfBuilders_WhenCallingBuildListExplicitly_ThenAListOfEntitiesOfTheRightTypeShouldBeReturned() + { + var builders = Builder.CreateListOfSize(5); + + var entities = builders.BuildList(); + + entities.ShouldBeAssignableTo>(); + } + + [Fact] + public void GivenListOfBuilders_WhenCallingBuildListImplicitly_ThenAListOfEntitiesOfTheRightTypeShouldBeReturned() + { + List entities = Builder.CreateListOfSize(5); + + entities.ShouldBeAssignableTo>(); + } + + [Fact] + public void GivenListOfBuilders_WhenCallingBuildListExplicitly_ThenAListOfUniqueEntitiesShouldBeReturned() + { + var builders = Builder.CreateListOfSize(5); + + var entities = builders.BuildList(); + + entities[0].ShouldNotBe(entities[1]); + entities[0].ShouldNotBe(entities[2]); + entities[0].ShouldNotBe(entities[3]); + entities[0].ShouldNotBe(entities[4]); + entities[1].ShouldNotBe(entities[2]); + entities[1].ShouldNotBe(entities[3]); + entities[1].ShouldNotBe(entities[4]); + entities[2].ShouldNotBe(entities[3]); + entities[2].ShouldNotBe(entities[4]); + entities[3].ShouldNotBe(entities[4]); + } + + [Fact] + public void GivenListOfBuilders_WhenCallingBuildListImplicitly_ThenAListOfUniqueEntitiesShouldBeReturned() + { + List entities = Builder.CreateListOfSize(5); + + entities[0].ShouldNotBe(entities[1]); + entities[0].ShouldNotBe(entities[2]); + entities[0].ShouldNotBe(entities[3]); + entities[0].ShouldNotBe(entities[4]); + entities[1].ShouldNotBe(entities[2]); + entities[1].ShouldNotBe(entities[3]); + entities[1].ShouldNotBe(entities[4]); + entities[2].ShouldNotBe(entities[3]); + entities[2].ShouldNotBe(entities[4]); + entities[3].ShouldNotBe(entities[4]); + } + + [Fact] + public void GivenListOfBuildersWithCustomisation_WhenBuildingEntitiesExplicitly_ThenTheCustomisationShouldTakeEffect() + { + var generator = new SequentialGenerator(0, 100); + var list = CustomerBuilder.CreateListOfSize(3) + .All().With(b => b.WithFirstName(generator.Generate().ToString())); + + var data = list.BuildList(); + + data.Select(c => c.FirstName).ToArray() + .ShouldBe(new[] { "0", "1", "2" }); + } + + [Fact] + public void GivenListOfBuildersWithCustomisation_WhenBuildingEntitiesImplicitly_ThenTheCustomisationShouldTakeEffect() + { + var generator = new SequentialGenerator(0, 100); + + List data = CustomerBuilder.CreateListOfSize(3) + .All().With(b => b.WithFirstName(generator.Generate().ToString())); + + data.Select(c => c.FirstName).ToArray() + .ShouldBe(new[] { "0", "1", "2" }); + } + + [Fact] + public void GivenListOfBuildersWithARangeOfCustomisationMethods_WhenBuildingEntitiesExplicitly_ThenThenTheListIsBuiltAndModifiedCorrectly() + { + var i = 0; + var customers = CustomerBuilder.CreateListOfSize(5) + .TheFirst(1).WithFirstName("First") + .TheNext(1).WithLastName("Next Last") + .TheLast(1).WithLastName("Last Last") + .ThePrevious(2).With(b => b.WithLastName("last" + (++i).ToString())) + .All().WhoJoinedIn(1999) + .BuildList(); + + customers.ShouldBeAssignableTo>(); + customers.Count.ShouldBe(5); + customers[0].FirstName.ShouldBe("First"); + customers[1].LastName.ShouldBe("Next Last"); + customers[2].LastName.ShouldBe("last1"); + customers[3].LastName.ShouldBe("last2"); + customers[4].LastName.ShouldBe("Last Last"); + customers.ShouldAllBe(c => c.YearJoined == 1999); + } + + [Fact] + public void GivenListOfBuildersWithARangeOfCustomisationMethods_WhenBuildingEntitiesImplicitly_ThenThenTheListIsBuiltAndModifiedCorrectly() + { + var i = 0; + List customers = CustomerBuilder.CreateListOfSize(5) + .TheFirst(1).WithFirstName("First") + .TheNext(1).WithLastName("Next Last") + .TheLast(1).WithLastName("Last Last") + .ThePrevious(2).With(b => b.WithLastName("last" + (++i).ToString())) + .All().WhoJoinedIn(1999); + + customers.ShouldBeAssignableTo>(); + customers.Count.ShouldBe(5); + customers[0].FirstName.ShouldBe("First"); + customers[1].LastName.ShouldBe("Next Last"); + customers[2].LastName.ShouldBe("last1"); + customers[3].LastName.ShouldBe("last2"); + customers[4].LastName.ShouldBe("Last Last"); + customers.ShouldAllBe(c => c.YearJoined == 1999); + } + + [Fact] + public void WhenBuildingEntitiesExplicitly_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); + } + + [Fact] + public void WhenBuildingEntitiesImplicitly_ThenTheAnonymousValueFixtureIsSharedAcrossBuilders() + { + List customers = CustomerBuilder.CreateListOfSize(5); + + 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); + } + } +} \ No newline at end of file diff --git a/TestStack.Dossier.Tests/BuilderBuildTests.cs b/TestStack.Dossier.Tests/BuilderBuildTests.cs new file mode 100644 index 0000000..6b38f91 --- /dev/null +++ b/TestStack.Dossier.Tests/BuilderBuildTests.cs @@ -0,0 +1,56 @@ +using Shouldly; +using TestStack.Dossier.Tests.Builders; +using TestStack.Dossier.Tests.Entities; +using Xunit; + +namespace TestStack.Dossier.Tests +{ + public class BuilderBuildTests + { + [Fact] + public void GivenBasicBuilder_WhenCallingBuildExplicitly_ThenReturnAnObject() + { + var builder = Builder.CreateNew(); + + var customer = builder.Build(); + + customer.ShouldBeOfType(); + } + + [Fact] + public void GivenBuilder_WhenCallingSetExplicitly_ShouldOverrideValues() + { + var builder = Builder.CreateNew() + .Set(x => x.FirstName, "Pi") + .Set(x => x.LastName, "Lanningham") + .Set(x => x.YearJoined, 2014); + + var customer = builder.Build(); + + customer.FirstName.ShouldBe("Pi"); + customer.LastName.ShouldBe("Lanningham"); + customer.YearJoined.ShouldBe(2014); + } + + [Fact] + public void GivenBasicBuilder_WhenCallingBuildImplicitly_ThenReturnAnObject() + { + Customer customer = Builder.CreateNew(); + + customer.ShouldBeOfType(); + } + + [Fact] + public void GivenBuilder_WhenCallingSetImplicitly_ShouldOverrideValues() + { + Customer customer = Builder.CreateNew() + .Set(x => x.FirstName, "Pi") + .Set(x => x.LastName, "Lanningham") + .Set(x => x.YearJoined, 2014); + + customer.FirstName.ShouldBe("Pi"); + customer.LastName.ShouldBe("Lanningham"); + customer.YearJoined.ShouldBe(2014); + } + } +} \ No newline at end of file diff --git a/TestStack.Dossier.Tests/GetAnonymousTests.cs b/TestStack.Dossier.Tests/GetAnonymousTests.cs index 442b556..c415c73 100644 --- a/TestStack.Dossier.Tests/GetAnonymousTests.cs +++ b/TestStack.Dossier.Tests/GetAnonymousTests.cs @@ -1,4 +1,5 @@ -using Shouldly; +using System; +using Shouldly; using TestStack.Dossier.DataSources.Person; using TestStack.Dossier.Lists; using TestStack.Dossier.Tests.Builders; @@ -113,9 +114,20 @@ public bool CanSupplyValue(string propertyName) && propertyName.ToLower().StartsWith("year"); } + public bool CanSupplyValue(Type type, string propertyName) + { + return type == typeof(int) + && propertyName.ToLower().StartsWith("year"); + } + public TValue GenerateAnonymousValue(AnonymousValueFixture any, string propertyName) { return (TValue)(object)_year++; } + + public object GenerateAnonymousValue(AnonymousValueFixture any, Type type, string propertyName) + { + return _year++; + } } } diff --git a/TestStack.Dossier.Tests/TestHelpers/StaticAnonymousValueSupplier.cs b/TestStack.Dossier.Tests/TestHelpers/StaticAnonymousValueSupplier.cs index dc3db91..4c7c9a0 100644 --- a/TestStack.Dossier.Tests/TestHelpers/StaticAnonymousValueSupplier.cs +++ b/TestStack.Dossier.Tests/TestHelpers/StaticAnonymousValueSupplier.cs @@ -1,4 +1,6 @@ -namespace TestStack.Dossier.Tests.TestHelpers +using System; + +namespace TestStack.Dossier.Tests.TestHelpers { public class StaticAnonymousValueSupplier : IAnonymousValueSupplier { @@ -14,9 +16,19 @@ public bool CanSupplyValue(string propertyName) return typeof(TValue) == _valueToSupply.GetType(); } + public bool CanSupplyValue(Type type, string propertyName) + { + return type == _valueToSupply.GetType(); + } + public TValue GenerateAnonymousValue(AnonymousValueFixture any, string propertyName) { return (TValue) _valueToSupply; } + + public object GenerateAnonymousValue(AnonymousValueFixture any, Type type, string propertyName) + { + return _valueToSupply; + } } } diff --git a/TestStack.Dossier.Tests/TestStack.Dossier.Tests.csproj b/TestStack.Dossier.Tests/TestStack.Dossier.Tests.csproj index 73d099b..0b2c2b0 100644 --- a/TestStack.Dossier.Tests/TestStack.Dossier.Tests.csproj +++ b/TestStack.Dossier.Tests/TestStack.Dossier.Tests.csproj @@ -54,6 +54,8 @@ + + diff --git a/TestStack.Dossier/AnonymousValueFixture.cs b/TestStack.Dossier/AnonymousValueFixture.cs index 64e193e..fc0311d 100644 --- a/TestStack.Dossier/AnonymousValueFixture.cs +++ b/TestStack.Dossier/AnonymousValueFixture.cs @@ -90,5 +90,15 @@ public T Get(Expression> property) return valueSupplier.GenerateAnonymousValue(this, propertyName); } + + public object Get(Type type, string propertyName) + { + var valueSupplier = LocalValueSuppliers + .Concat(GlobalValueSuppliers) + .Concat(DefaultValueSuppliers) + .First(s => s.CanSupplyValue(type,propertyName)); + + return valueSupplier.GenerateAnonymousValue(this, type, propertyName); + } } } diff --git a/TestStack.Dossier/Builder.cs b/TestStack.Dossier/Builder.cs new file mode 100644 index 0000000..ca9fd3b --- /dev/null +++ b/TestStack.Dossier/Builder.cs @@ -0,0 +1,13 @@ +using System; + +namespace TestStack.Dossier +{ + public class Builder : TestDataBuilder> + where T : class + { + public static Builder CreateNew() + { + return new Builder(); + } + } +} diff --git a/TestStack.Dossier/IAnonymousValueSupplier.cs b/TestStack.Dossier/IAnonymousValueSupplier.cs index eae1839..9ead160 100644 --- a/TestStack.Dossier/IAnonymousValueSupplier.cs +++ b/TestStack.Dossier/IAnonymousValueSupplier.cs @@ -1,4 +1,6 @@ -namespace TestStack.Dossier +using System; + +namespace TestStack.Dossier { /// /// Inheritors can supply an anonymous value. @@ -14,6 +16,14 @@ public interface IAnonymousValueSupplier /// Whether or not this supplier can supply an anonymous value bool CanSupplyValue(string propertyName); + /// + /// Returns whether or not this supplier can supply an anonymous value for the given property. + /// + /// The type of the property to generate a value for + /// The name of the property to generate a value for + /// Whether or not this supplier can supply an anonymous value + bool CanSupplyValue(Type type, string propertyName); + /// /// Return an anonymous value for the given property and fixture. /// @@ -23,5 +33,15 @@ public interface IAnonymousValueSupplier /// The name of the property to return an anonymous value for /// The anonymous value TValue GenerateAnonymousValue(AnonymousValueFixture any, string propertyName); + + /// + /// Return an anonymous value for the given property and fixture. + /// + /// The type that the property is enclosed in + /// The type of the target property - the required anonymous value is of this type + /// Anonymous value fixture + /// The name of the property to return an anonymous value for + /// The anonymous value + object GenerateAnonymousValue(AnonymousValueFixture any, Type type, string propertyName); } } diff --git a/TestStack.Dossier/PropertyNameGetter.cs b/TestStack.Dossier/PropertyNameGetter.cs index 2270e16..df0de58 100644 --- a/TestStack.Dossier/PropertyNameGetter.cs +++ b/TestStack.Dossier/PropertyNameGetter.cs @@ -1,5 +1,7 @@ using System; +using System.Linq; using System.Linq.Expressions; +using System.Reflection; namespace TestStack.Dossier { @@ -20,5 +22,29 @@ public static string Get(Expression> prop return memExp.Member.Name; } + + public static ConstructorInfo GetConstructor(Type type) + { + if (type == null) + throw new ArgumentNullException("type"); + + var ctors = type.GetConstructors() + .OrderByDescending(x => x.GetParameters().Length) + .ToArray(); + + if (ctors.Length == 0) + throw new InvalidOperationException(string.Format("The given type {0} does not contain any public constructors.", type.Name)); + + if (ctors.Length > 1 && ctors[0].GetParameters().Length == ctors[1].GetParameters().Length) + throw new InvalidOperationException(string.Format("Can't select best suited constructor between {0} and {1}.", GetConstructorSignature(ctors[0]), GetConstructorSignature(ctors[1]))); + + return ctors[0]; + } + + public static string GetConstructorSignature(ConstructorInfo ctor) + { + var typeName = ctor.DeclaringType == null ? "" : ctor.DeclaringType.Name; + return typeName + ctor.ToString().Substring("Void ".Length); + } } } diff --git a/TestStack.Dossier/Suppliers/DefaultEmailValueSupplier.cs b/TestStack.Dossier/Suppliers/DefaultEmailValueSupplier.cs index 2ea3b4a..9c1cd55 100644 --- a/TestStack.Dossier/Suppliers/DefaultEmailValueSupplier.cs +++ b/TestStack.Dossier/Suppliers/DefaultEmailValueSupplier.cs @@ -1,4 +1,5 @@ -using TestStack.Dossier.EquivalenceClasses.Person; +using System; +using TestStack.Dossier.EquivalenceClasses.Person; namespace TestStack.Dossier.Suppliers { @@ -10,7 +11,13 @@ public class DefaultEmailValueSupplier : IAnonymousValueSupplier /// public bool CanSupplyValue(string propertyName) { - return typeof (TValue) == typeof(string) && propertyName.ToLower().Contains("email"); + return CanSupplyValue(typeof(string), propertyName); + } + + /// + public bool CanSupplyValue(Type type, string propertyName) + { + return type == typeof(string) && propertyName.ToLower().Contains("email"); } /// @@ -18,5 +25,11 @@ public TValue GenerateAnonymousValue(AnonymousValueFixture any, { return (TValue) (object) any.EmailAddress(); } + + /// + public object GenerateAnonymousValue(AnonymousValueFixture any, Type type, string propertyName) + { + return any.EmailAddress(); + } } } diff --git a/TestStack.Dossier/Suppliers/DefaultFirstNameValueSupplier.cs b/TestStack.Dossier/Suppliers/DefaultFirstNameValueSupplier.cs index 10251ca..2ab4fe8 100644 --- a/TestStack.Dossier/Suppliers/DefaultFirstNameValueSupplier.cs +++ b/TestStack.Dossier/Suppliers/DefaultFirstNameValueSupplier.cs @@ -1,4 +1,5 @@ -using TestStack.Dossier.EquivalenceClasses.Person; +using System; +using TestStack.Dossier.EquivalenceClasses.Person; namespace TestStack.Dossier.Suppliers { @@ -10,7 +11,13 @@ public class DefaultFirstNameValueSupplier : IAnonymousValueSupplier /// public bool CanSupplyValue(string propertyName) { - return typeof (TValue) == typeof(string) && propertyName.ToLower() == "firstname"; + return CanSupplyValue(typeof (TValue), propertyName); + } + + /// + public bool CanSupplyValue(Type type, string propertyName) + { + return type == typeof(string) && propertyName.ToLower() == "firstname"; } /// @@ -18,5 +25,11 @@ public TValue GenerateAnonymousValue(AnonymousValueFixture any, { return (TValue) (object) any.FirstName(); } + + /// + public object GenerateAnonymousValue(AnonymousValueFixture any, Type type, string propertyName) + { + return any.FirstName(); + } } } diff --git a/TestStack.Dossier/Suppliers/DefaultLastNameValueSupplier.cs b/TestStack.Dossier/Suppliers/DefaultLastNameValueSupplier.cs index 522bd4e..d188e23 100644 --- a/TestStack.Dossier/Suppliers/DefaultLastNameValueSupplier.cs +++ b/TestStack.Dossier/Suppliers/DefaultLastNameValueSupplier.cs @@ -1,4 +1,5 @@ -using TestStack.Dossier.EquivalenceClasses.Person; +using System; +using TestStack.Dossier.EquivalenceClasses.Person; namespace TestStack.Dossier.Suppliers { @@ -14,10 +15,23 @@ public bool CanSupplyValue(string propertyName) (propertyName.ToLower() == "lastname" || propertyName.ToLower() == "surname"); } + /// + public bool CanSupplyValue(Type type, string propertyName) + { + return type == typeof(string) && + (propertyName.ToLower() == "lastname" || propertyName.ToLower() == "surname"); + } + /// public TValue GenerateAnonymousValue(AnonymousValueFixture any, string propertyName) { - return (TValue) (object) any.LastName(); + return (TValue)(object)any.LastName(); + } + + /// + public object GenerateAnonymousValue(AnonymousValueFixture any, Type type, string propertyName) + { + return any.LastName(); } } } diff --git a/TestStack.Dossier/Suppliers/DefaultStringValueSupplier.cs b/TestStack.Dossier/Suppliers/DefaultStringValueSupplier.cs index f63b4a3..0381230 100644 --- a/TestStack.Dossier/Suppliers/DefaultStringValueSupplier.cs +++ b/TestStack.Dossier/Suppliers/DefaultStringValueSupplier.cs @@ -1,4 +1,5 @@ -using TestStack.Dossier.EquivalenceClasses; +using System; +using TestStack.Dossier.EquivalenceClasses; namespace TestStack.Dossier.Suppliers { @@ -13,10 +14,22 @@ public bool CanSupplyValue(string propertyName) return typeof (TValue) == typeof(string); } + /// + public bool CanSupplyValue(Type type, string propertyName) + { + return type == typeof(string); + } + /// public TValue GenerateAnonymousValue(AnonymousValueFixture any, string propertyName) { return (TValue) (object) any.StringStartingWith(propertyName); } + + /// + public object GenerateAnonymousValue(AnonymousValueFixture any, Type type, string propertyName) + { + return any.StringStartingWith(propertyName); + } } } diff --git a/TestStack.Dossier/Suppliers/DefaultValueSupplier.cs b/TestStack.Dossier/Suppliers/DefaultValueSupplier.cs index bd1ed89..775c699 100644 --- a/TestStack.Dossier/Suppliers/DefaultValueSupplier.cs +++ b/TestStack.Dossier/Suppliers/DefaultValueSupplier.cs @@ -1,4 +1,6 @@ -namespace TestStack.Dossier.Suppliers +using System; + +namespace TestStack.Dossier.Suppliers { /// /// Supplies default value for any type. @@ -11,10 +13,27 @@ public bool CanSupplyValue(string propertyName) return true; } + /// + public bool CanSupplyValue(Type type, string propertyName) + { + return true; + } + /// public TValue GenerateAnonymousValue(AnonymousValueFixture any, string propertyName) { return default(TValue); } + + /// + public object GenerateAnonymousValue(AnonymousValueFixture any, Type type, string propertyName) + { + // See stackoverflow: http://stackoverflow.com/questions/325426/programmatic-equivalent-of-defaulttype + if (type.IsValueType) + { + return Activator.CreateInstance(type); + } + return null; + } } } diff --git a/TestStack.Dossier/Suppliers/DefaultValueTypeValueSupplier.cs b/TestStack.Dossier/Suppliers/DefaultValueTypeValueSupplier.cs index 4495ffa..03ad33d 100644 --- a/TestStack.Dossier/Suppliers/DefaultValueTypeValueSupplier.cs +++ b/TestStack.Dossier/Suppliers/DefaultValueTypeValueSupplier.cs @@ -1,4 +1,7 @@ -using Ploeh.AutoFixture; +using System; +using System.Linq; +using Ploeh.AutoFixture; +using Ploeh.AutoFixture.Kernel; namespace TestStack.Dossier.Suppliers { @@ -13,10 +16,26 @@ public bool CanSupplyValue(string propertyName) return typeof (TValue).IsValueType; } + /// + public bool CanSupplyValue(Type type, string propertyName) + { + return type.IsValueType; + } + /// public TValue GenerateAnonymousValue(AnonymousValueFixture any, string propertyName) { return any.Fixture.Create(); } + + /// How to create weakly-typed CreateAnonymous with AutoFixture + /// http://autofixture.codeplex.com/workitem/4229 + /// + public object GenerateAnonymousValue(AnonymousValueFixture any, Type type, string propertyName) + { + var context = new SpecimenContext(any.Fixture); + var specimen = context.Resolve(type); + return specimen; + } } } diff --git a/TestStack.Dossier/TestDataBuilder.cs b/TestStack.Dossier/TestDataBuilder.cs index 078be5d..496a571 100644 --- a/TestStack.Dossier/TestDataBuilder.cs +++ b/TestStack.Dossier/TestDataBuilder.cs @@ -1,7 +1,8 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Linq.Expressions; +using System.Reflection; +using Ploeh.AutoFixture; using TestStack.Dossier.Lists; namespace TestStack.Dossier @@ -71,10 +72,22 @@ public static implicit operator List(TestDataBuilder } /// - /// Build the actual object - override this and call the constructor and any other methods. + /// Build the actual object - you can optionally override this and call the constructor and any other methods. /// /// The built object - protected abstract TObject BuildObject(); + protected virtual TObject BuildObject() + { + var model = Any.Fixture.Create(); + + var properties = typeof (TObject).GetProperties(BindingFlags.Public | BindingFlags.Instance); + foreach (var property in properties) + { + var val = Get(property.PropertyType, property.Name); + property.SetValue(model, val, null); + } + + return model; + } /// /// Return an NSubstitute proxy object when .Build() is called rather than a real object. @@ -120,6 +133,13 @@ public TValue Get(Expression> property) return (TValue)_properties[PropertyNameGetter.Get(property)]; } + public object Get(Type type, string propertyName) + { + if (!Has(propertyName)) + return Any.Get(type, propertyName); + return _properties[propertyName]; + } + /// /// Gets the recorded value for the given property from {TObject} or if no /// value has been recorded the default value for {TValue}. @@ -154,7 +174,17 @@ public static ListBuilder CreateListOfSize(int size) /// Whether or not there is a recorded value for the property protected bool Has(Expression> property) { - return _properties.ContainsKey(PropertyNameGetter.Get(property)); + return Has(PropertyNameGetter.Get(property)); + } + + /// + /// Returns whether or not there is currently an explicit value recorded against the given property from {TObject}. + /// + /// A string specifying the name of the property to retrieve the recorded value for + /// Whether or not there is a recorded value for the property + protected bool Has(string propertyName) + { + return _properties.ContainsKey(propertyName); } /// diff --git a/TestStack.Dossier/TestStack.Dossier.csproj b/TestStack.Dossier/TestStack.Dossier.csproj index 607d3e4..1b18a57 100644 --- a/TestStack.Dossier/TestStack.Dossier.csproj +++ b/TestStack.Dossier/TestStack.Dossier.csproj @@ -51,6 +51,7 @@ + From c57abec3a144a339c4807b3c1a6cbd13716b7aed Mon Sep 17 00:00:00 2001 From: Michael Whelan Date: Sun, 26 Apr 2015 11:30:20 +0100 Subject: [PATCH 02/10] renamed PropertyNameGetter to Reflector to show additional behaviour --- README.md | 1 + TestStack.Dossier/AnonymousValueFixture.cs | 2 +- TestStack.Dossier/PropertyNameGetter.cs | 50 ---------------------- TestStack.Dossier/ProxyBuilder.cs | 2 +- TestStack.Dossier/Reflector.cs | 30 +++++++++++++ TestStack.Dossier/TestDataBuilder.cs | 8 ++-- TestStack.Dossier/TestStack.Dossier.csproj | 2 +- 7 files changed, 38 insertions(+), 57 deletions(-) delete mode 100644 TestStack.Dossier/PropertyNameGetter.cs create mode 100644 TestStack.Dossier/Reflector.cs diff --git a/README.md b/README.md index 4851392..3eeb2f8 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,7 @@ Prior to v2.0 this library was known as NTestDataBuilder. } } +Note that you can optionally override the `BuildObject` method if you want full control over how your object is constructed, for example if you want to use a particular constructor. If you don't provide this then Dossier will create the object for you. 3. Use the builder in a test, e.g. diff --git a/TestStack.Dossier/AnonymousValueFixture.cs b/TestStack.Dossier/AnonymousValueFixture.cs index fc0311d..b9bc447 100644 --- a/TestStack.Dossier/AnonymousValueFixture.cs +++ b/TestStack.Dossier/AnonymousValueFixture.cs @@ -82,7 +82,7 @@ public AnonymousValueFixture() /// The anonymous value, taking into account any registered conventions public T Get(Expression> property) { - var propertyName = PropertyNameGetter.Get(property); + var propertyName = Reflector.GetPropertyFor(property); var valueSupplier = LocalValueSuppliers .Concat(GlobalValueSuppliers) .Concat(DefaultValueSuppliers) diff --git a/TestStack.Dossier/PropertyNameGetter.cs b/TestStack.Dossier/PropertyNameGetter.cs deleted file mode 100644 index df0de58..0000000 --- a/TestStack.Dossier/PropertyNameGetter.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; - -namespace TestStack.Dossier -{ - internal static class PropertyNameGetter - { - public static string Get(Expression> property) - { - var memExp = property.Body as MemberExpression; - if (memExp == null) - throw new ArgumentException( - string.Format( - "Given property expression ({0}) didn't specify a property on {1}", - property, - typeof(TObject).Name - ), - "property" - ); - - return memExp.Member.Name; - } - - public static ConstructorInfo GetConstructor(Type type) - { - if (type == null) - throw new ArgumentNullException("type"); - - var ctors = type.GetConstructors() - .OrderByDescending(x => x.GetParameters().Length) - .ToArray(); - - if (ctors.Length == 0) - throw new InvalidOperationException(string.Format("The given type {0} does not contain any public constructors.", type.Name)); - - if (ctors.Length > 1 && ctors[0].GetParameters().Length == ctors[1].GetParameters().Length) - throw new InvalidOperationException(string.Format("Can't select best suited constructor between {0} and {1}.", GetConstructorSignature(ctors[0]), GetConstructorSignature(ctors[1]))); - - return ctors[0]; - } - - public static string GetConstructorSignature(ConstructorInfo ctor) - { - var typeName = ctor.DeclaringType == null ? "" : ctor.DeclaringType.Name; - return typeName + ctor.ToString().Substring("Void ".Length); - } - } -} diff --git a/TestStack.Dossier/ProxyBuilder.cs b/TestStack.Dossier/ProxyBuilder.cs index 306f79d..5a7ff05 100644 --- a/TestStack.Dossier/ProxyBuilder.cs +++ b/TestStack.Dossier/ProxyBuilder.cs @@ -29,7 +29,7 @@ public ProxyBuilder(Dictionary properties) public T Build() { var proxy = Substitute.For(); - var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance); + var properties = Reflector.GetSettablePropertiesFor(); foreach (var property in properties.Where(property => _properties.ContainsKey(property.Name))) { if (property.GetGetMethod().IsVirtual) diff --git a/TestStack.Dossier/Reflector.cs b/TestStack.Dossier/Reflector.cs new file mode 100644 index 0000000..bd6c5c6 --- /dev/null +++ b/TestStack.Dossier/Reflector.cs @@ -0,0 +1,30 @@ +using System; +using System.Linq.Expressions; +using System.Reflection; + +namespace TestStack.Dossier +{ + internal static class Reflector + { + public static string GetPropertyFor(Expression> property) + { + var memExp = property.Body as MemberExpression; + if (memExp == null) + throw new ArgumentException( + string.Format( + "Given property expression ({0}) didn't specify a property on {1}", + property, + typeof(TObject).Name + ), + "property" + ); + + return memExp.Member.Name; + } + + public static PropertyInfo[] GetSettablePropertiesFor() + { + return typeof (TObject).GetProperties(BindingFlags.Public | BindingFlags.Instance); + } + } +} diff --git a/TestStack.Dossier/TestDataBuilder.cs b/TestStack.Dossier/TestDataBuilder.cs index 496a571..00ec434 100644 --- a/TestStack.Dossier/TestDataBuilder.cs +++ b/TestStack.Dossier/TestDataBuilder.cs @@ -79,7 +79,7 @@ protected virtual TObject BuildObject() { var model = Any.Fixture.Create(); - var properties = typeof (TObject).GetProperties(BindingFlags.Public | BindingFlags.Instance); + var properties = Reflector.GetSettablePropertiesFor(); foreach (var property in properties) { var val = Get(property.PropertyType, property.Name); @@ -114,7 +114,7 @@ protected virtual void AlterProxy(TObject proxy) {} /// The value to record public TBuilder Set(Expression> property, TValue value) { - _properties[PropertyNameGetter.Get(property)] = value; + _properties[Reflector.GetPropertyFor(property)] = value; return this as TBuilder; } @@ -130,7 +130,7 @@ public TValue Get(Expression> property) if (!Has(property)) return Any.Get(property); - return (TValue)_properties[PropertyNameGetter.Get(property)]; + return (TValue)_properties[Reflector.GetPropertyFor(property)]; } public object Get(Type type, string propertyName) @@ -174,7 +174,7 @@ public static ListBuilder CreateListOfSize(int size) /// Whether or not there is a recorded value for the property protected bool Has(Expression> property) { - return Has(PropertyNameGetter.Get(property)); + return Has(Reflector.GetPropertyFor(property)); } /// diff --git a/TestStack.Dossier/TestStack.Dossier.csproj b/TestStack.Dossier/TestStack.Dossier.csproj index 1b18a57..c7f8187 100644 --- a/TestStack.Dossier/TestStack.Dossier.csproj +++ b/TestStack.Dossier/TestStack.Dossier.csproj @@ -87,7 +87,7 @@ - + From 48efca48a214459e1a9725b5b5d0f33e89f24bb2 Mon Sep 17 00:00:00 2001 From: Michael Whelan Date: Sun, 26 Apr 2015 19:03:58 +0100 Subject: [PATCH 03/10] removed generic CanSupply from IAnonymousValueSupplier --- TestStack.Dossier/AnonymousValueFixture.cs | 2 +- TestStack.Dossier/IAnonymousValueSupplier.cs | 9 --------- TestStack.Dossier/Suppliers/DefaultEmailValueSupplier.cs | 6 ------ .../Suppliers/DefaultFirstNameValueSupplier.cs | 6 ------ .../Suppliers/DefaultLastNameValueSupplier.cs | 7 ------- .../Suppliers/DefaultStringValueSupplier.cs | 6 ------ TestStack.Dossier/Suppliers/DefaultValueSupplier.cs | 6 ------ .../Suppliers/DefaultValueTypeValueSupplier.cs | 6 ------ 8 files changed, 1 insertion(+), 47 deletions(-) diff --git a/TestStack.Dossier/AnonymousValueFixture.cs b/TestStack.Dossier/AnonymousValueFixture.cs index b9bc447..0d26193 100644 --- a/TestStack.Dossier/AnonymousValueFixture.cs +++ b/TestStack.Dossier/AnonymousValueFixture.cs @@ -86,7 +86,7 @@ public T Get(Expression> property) var valueSupplier = LocalValueSuppliers .Concat(GlobalValueSuppliers) .Concat(DefaultValueSuppliers) - .First(s => s.CanSupplyValue(propertyName)); + .First(s => s.CanSupplyValue(typeof(T), propertyName)); return valueSupplier.GenerateAnonymousValue(this, propertyName); } diff --git a/TestStack.Dossier/IAnonymousValueSupplier.cs b/TestStack.Dossier/IAnonymousValueSupplier.cs index 9ead160..493debc 100644 --- a/TestStack.Dossier/IAnonymousValueSupplier.cs +++ b/TestStack.Dossier/IAnonymousValueSupplier.cs @@ -7,15 +7,6 @@ namespace TestStack.Dossier /// public interface IAnonymousValueSupplier { - /// - /// Returns whether or not this supplier can supply an anonymous value for the given property. - /// - /// The type that the property is enclosed in - /// The type of the target property - the anonymous value will need to be of this type - /// The name of the property to generate a value for - /// Whether or not this supplier can supply an anonymous value - bool CanSupplyValue(string propertyName); - /// /// Returns whether or not this supplier can supply an anonymous value for the given property. /// diff --git a/TestStack.Dossier/Suppliers/DefaultEmailValueSupplier.cs b/TestStack.Dossier/Suppliers/DefaultEmailValueSupplier.cs index 9c1cd55..754faba 100644 --- a/TestStack.Dossier/Suppliers/DefaultEmailValueSupplier.cs +++ b/TestStack.Dossier/Suppliers/DefaultEmailValueSupplier.cs @@ -8,12 +8,6 @@ namespace TestStack.Dossier.Suppliers /// public class DefaultEmailValueSupplier : IAnonymousValueSupplier { - /// - public bool CanSupplyValue(string propertyName) - { - return CanSupplyValue(typeof(string), propertyName); - } - /// public bool CanSupplyValue(Type type, string propertyName) { diff --git a/TestStack.Dossier/Suppliers/DefaultFirstNameValueSupplier.cs b/TestStack.Dossier/Suppliers/DefaultFirstNameValueSupplier.cs index 2ab4fe8..bbd2e59 100644 --- a/TestStack.Dossier/Suppliers/DefaultFirstNameValueSupplier.cs +++ b/TestStack.Dossier/Suppliers/DefaultFirstNameValueSupplier.cs @@ -8,12 +8,6 @@ namespace TestStack.Dossier.Suppliers /// public class DefaultFirstNameValueSupplier : IAnonymousValueSupplier { - /// - public bool CanSupplyValue(string propertyName) - { - return CanSupplyValue(typeof (TValue), propertyName); - } - /// public bool CanSupplyValue(Type type, string propertyName) { diff --git a/TestStack.Dossier/Suppliers/DefaultLastNameValueSupplier.cs b/TestStack.Dossier/Suppliers/DefaultLastNameValueSupplier.cs index d188e23..e0fc9c7 100644 --- a/TestStack.Dossier/Suppliers/DefaultLastNameValueSupplier.cs +++ b/TestStack.Dossier/Suppliers/DefaultLastNameValueSupplier.cs @@ -8,13 +8,6 @@ namespace TestStack.Dossier.Suppliers /// public class DefaultLastNameValueSupplier : IAnonymousValueSupplier { - /// - public bool CanSupplyValue(string propertyName) - { - return typeof (TValue) == typeof(string) && - (propertyName.ToLower() == "lastname" || propertyName.ToLower() == "surname"); - } - /// public bool CanSupplyValue(Type type, string propertyName) { diff --git a/TestStack.Dossier/Suppliers/DefaultStringValueSupplier.cs b/TestStack.Dossier/Suppliers/DefaultStringValueSupplier.cs index 0381230..ed5b40f 100644 --- a/TestStack.Dossier/Suppliers/DefaultStringValueSupplier.cs +++ b/TestStack.Dossier/Suppliers/DefaultStringValueSupplier.cs @@ -8,12 +8,6 @@ namespace TestStack.Dossier.Suppliers /// public class DefaultStringValueSupplier : IAnonymousValueSupplier { - /// - public bool CanSupplyValue(string propertyName) - { - return typeof (TValue) == typeof(string); - } - /// public bool CanSupplyValue(Type type, string propertyName) { diff --git a/TestStack.Dossier/Suppliers/DefaultValueSupplier.cs b/TestStack.Dossier/Suppliers/DefaultValueSupplier.cs index 775c699..6bd6099 100644 --- a/TestStack.Dossier/Suppliers/DefaultValueSupplier.cs +++ b/TestStack.Dossier/Suppliers/DefaultValueSupplier.cs @@ -7,12 +7,6 @@ namespace TestStack.Dossier.Suppliers /// public class DefaultValueSupplier : IAnonymousValueSupplier { - /// - public bool CanSupplyValue(string propertyName) - { - return true; - } - /// public bool CanSupplyValue(Type type, string propertyName) { diff --git a/TestStack.Dossier/Suppliers/DefaultValueTypeValueSupplier.cs b/TestStack.Dossier/Suppliers/DefaultValueTypeValueSupplier.cs index 03ad33d..bf1cd68 100644 --- a/TestStack.Dossier/Suppliers/DefaultValueTypeValueSupplier.cs +++ b/TestStack.Dossier/Suppliers/DefaultValueTypeValueSupplier.cs @@ -10,12 +10,6 @@ namespace TestStack.Dossier.Suppliers /// public class DefaultValueTypeValueSupplier : IAnonymousValueSupplier { - /// - public bool CanSupplyValue(string propertyName) - { - return typeof (TValue).IsValueType; - } - /// public bool CanSupplyValue(Type type, string propertyName) { From 7632277d79a9ea83937d9b4bcf34ffbc282c456c Mon Sep 17 00:00:00 2001 From: Michael Whelan Date: Tue, 28 Apr 2015 19:32:53 +0100 Subject: [PATCH 04/10] Updated PR to apply Rob's suggestions. --- README.md | 2 +- TestStack.Dossier.Tests/BuildListTests.cs | 24 +--- TestStack.Dossier.Tests/BuildTests.cs | 2 +- .../BuilderBuildListTests.cs | 113 +++++++----------- TestStack.Dossier.Tests/BuilderBuildTests.cs | 16 ++- .../Builders/BasicCustomerBuilder.cs | 2 +- .../Builders/CustomerBuilder.cs | 2 +- .../Builders/ProxyAlteringCustomerBuilder.cs | 2 +- .../Builders/StudentViewModelBuilder.cs | 23 ++++ TestStack.Dossier.Tests/ProxyBuilderTests.cs | 2 +- .../{ => Stubs}/Entities/Company.cs | 2 +- .../{ => Stubs}/Entities/Customer.cs | 4 +- .../{ => Stubs}/Entities/CustomerClass.cs | 2 +- .../Stubs/ViewModels/Grade.cs | 7 ++ .../Stubs/ViewModels/InstructorViewModel.cs | 30 +++++ .../Stubs/ViewModels/StudentViewModel.cs | 35 ++++++ .../TestStack.Dossier.Tests.csproj | 11 +- TestStack.Dossier/AnonymousValueFixture.cs | 2 +- TestStack.Dossier/Reflector.cs | 2 +- TestStack.Dossier/TestDataBuilder.cs | 13 +- 20 files changed, 186 insertions(+), 110 deletions(-) create mode 100644 TestStack.Dossier.Tests/Builders/StudentViewModelBuilder.cs rename TestStack.Dossier.Tests/{ => Stubs}/Entities/Company.cs (86%) rename TestStack.Dossier.Tests/{ => Stubs}/Entities/Customer.cs (95%) rename TestStack.Dossier.Tests/{ => Stubs}/Entities/CustomerClass.cs (70%) create mode 100644 TestStack.Dossier.Tests/Stubs/ViewModels/Grade.cs create mode 100644 TestStack.Dossier.Tests/Stubs/ViewModels/InstructorViewModel.cs create mode 100644 TestStack.Dossier.Tests/Stubs/ViewModels/StudentViewModel.cs diff --git a/README.md b/README.md index 3eeb2f8..f0b394d 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ Prior to v2.0 this library was known as NTestDataBuilder. } } -Note that you can optionally override the `BuildObject` method if you want full control over how your object is constructed, for example if you want to use a particular constructor. If you don't provide this then Dossier will create the object for you. +Note that overriding the BuildObject is optional. It can be useful to do this if you want full control over how your object is constructed, for example if you want to use a particular constructor. If you don't choose to override this method then Dossier will create the object for you. 3. Use the builder in a test, e.g. diff --git a/TestStack.Dossier.Tests/BuildListTests.cs b/TestStack.Dossier.Tests/BuildListTests.cs index 2b498db..e2651b2 100644 --- a/TestStack.Dossier.Tests/BuildListTests.cs +++ b/TestStack.Dossier.Tests/BuildListTests.cs @@ -4,7 +4,7 @@ using TestStack.Dossier.DataSources.Generators; using TestStack.Dossier.Lists; using TestStack.Dossier.Tests.Builders; -using TestStack.Dossier.Tests.Entities; +using TestStack.Dossier.Tests.Stubs.Entities; using Xunit; namespace TestStack.Dossier.Tests @@ -70,16 +70,7 @@ public void GivenListOfBuilders_WhenCallingBuildListExplicitly_ThenAListOfUnique var entities = builders.BuildList(); - entities[0].ShouldNotBe(entities[1]); - entities[0].ShouldNotBe(entities[2]); - entities[0].ShouldNotBe(entities[3]); - entities[0].ShouldNotBe(entities[4]); - entities[1].ShouldNotBe(entities[2]); - entities[1].ShouldNotBe(entities[3]); - entities[1].ShouldNotBe(entities[4]); - entities[2].ShouldNotBe(entities[3]); - entities[2].ShouldNotBe(entities[4]); - entities[3].ShouldNotBe(entities[4]); + entities.ShouldBeUnique(); } [Fact] @@ -87,16 +78,7 @@ public void GivenListOfBuilders_WhenCallingBuildListImplicitly_ThenAListOfUnique { List entities = BasicCustomerBuilder.CreateListOfSize(5); - entities[0].ShouldNotBe(entities[1]); - entities[0].ShouldNotBe(entities[2]); - entities[0].ShouldNotBe(entities[3]); - entities[0].ShouldNotBe(entities[4]); - entities[1].ShouldNotBe(entities[2]); - entities[1].ShouldNotBe(entities[3]); - entities[1].ShouldNotBe(entities[4]); - entities[2].ShouldNotBe(entities[3]); - entities[2].ShouldNotBe(entities[4]); - entities[3].ShouldNotBe(entities[4]); + entities.ShouldBeUnique(); } [Fact] diff --git a/TestStack.Dossier.Tests/BuildTests.cs b/TestStack.Dossier.Tests/BuildTests.cs index c2fcdf6..f220d62 100644 --- a/TestStack.Dossier.Tests/BuildTests.cs +++ b/TestStack.Dossier.Tests/BuildTests.cs @@ -1,6 +1,6 @@ using Shouldly; using TestStack.Dossier.Tests.Builders; -using TestStack.Dossier.Tests.Entities; +using TestStack.Dossier.Tests.Stubs.Entities; using Xunit; namespace TestStack.Dossier.Tests diff --git a/TestStack.Dossier.Tests/BuilderBuildListTests.cs b/TestStack.Dossier.Tests/BuilderBuildListTests.cs index 658815e..458e112 100644 --- a/TestStack.Dossier.Tests/BuilderBuildListTests.cs +++ b/TestStack.Dossier.Tests/BuilderBuildListTests.cs @@ -1,20 +1,23 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using Shouldly; using TestStack.Dossier.DataSources.Generators; using TestStack.Dossier.Lists; using TestStack.Dossier.Tests.Builders; -using TestStack.Dossier.Tests.Entities; +using TestStack.Dossier.Tests.Stubs.ViewModels; using Xunit; namespace TestStack.Dossier.Tests { public class BuilderBuildListTests { + private DateTime _enrollmentDate = new DateTime(2004, 9, 9); + [Fact] public void GivenANormalBuilderInstance_WhenCallingIsListBuilderProxy_ThenReturnFalse() { - var builder = Builder.CreateNew(); + var builder = Builder.CreateNew(); builder.IsListBuilderProxy().ShouldBe(false); } @@ -22,7 +25,7 @@ public void GivenANormalBuilderInstance_WhenCallingIsListBuilderProxy_ThenReturn [Fact] public void GivenAListBuilderProxyInstance_WhenCallingIsListBuilderProxy_ThenReturnTrue() { - var builder = Builder.CreateListOfSize(1).TheFirst(1); + var builder = Builder.CreateListOfSize(1).TheFirst(1); builder.IsListBuilderProxy().ShouldBe(true); } @@ -30,7 +33,7 @@ public void GivenAListBuilderProxyInstance_WhenCallingIsListBuilderProxy_ThenRet [Fact] public void GivenListOfBuilders_WhenCallingBuildListExplicitly_ThenAListOfEntitiesOfTheRightSizeShouldBeReturned() { - var builders = Builder.CreateListOfSize(5); + var builders = Builder.CreateListOfSize(5); var entities = builders.BuildList(); @@ -40,7 +43,7 @@ public void GivenListOfBuilders_WhenCallingBuildListExplicitly_ThenAListOfEntiti [Fact] public void GivenListOfBuilders_WhenCallingBuildListImplicitly_ThenAListOfEntitiesOfTheRightSizeShouldBeReturned() { - List entities = Builder.CreateListOfSize(5); + List entities = Builder.CreateListOfSize(5); entities.Count.ShouldBe(5); } @@ -48,62 +51,44 @@ public void GivenListOfBuilders_WhenCallingBuildListImplicitly_ThenAListOfEntiti [Fact] public void GivenListOfBuilders_WhenCallingBuildListExplicitly_ThenAListOfEntitiesOfTheRightTypeShouldBeReturned() { - var builders = Builder.CreateListOfSize(5); + var builders = Builder.CreateListOfSize(5); var entities = builders.BuildList(); - entities.ShouldBeAssignableTo>(); + entities.ShouldBeAssignableTo>(); } [Fact] public void GivenListOfBuilders_WhenCallingBuildListImplicitly_ThenAListOfEntitiesOfTheRightTypeShouldBeReturned() { - List entities = Builder.CreateListOfSize(5); + List entities = Builder.CreateListOfSize(5); - entities.ShouldBeAssignableTo>(); + entities.ShouldBeAssignableTo>(); } [Fact] public void GivenListOfBuilders_WhenCallingBuildListExplicitly_ThenAListOfUniqueEntitiesShouldBeReturned() { - var builders = Builder.CreateListOfSize(5); + var builders = Builder.CreateListOfSize(5); var entities = builders.BuildList(); - entities[0].ShouldNotBe(entities[1]); - entities[0].ShouldNotBe(entities[2]); - entities[0].ShouldNotBe(entities[3]); - entities[0].ShouldNotBe(entities[4]); - entities[1].ShouldNotBe(entities[2]); - entities[1].ShouldNotBe(entities[3]); - entities[1].ShouldNotBe(entities[4]); - entities[2].ShouldNotBe(entities[3]); - entities[2].ShouldNotBe(entities[4]); - entities[3].ShouldNotBe(entities[4]); + entities.ShouldBeUnique(); } [Fact] public void GivenListOfBuilders_WhenCallingBuildListImplicitly_ThenAListOfUniqueEntitiesShouldBeReturned() { - List entities = Builder.CreateListOfSize(5); - - entities[0].ShouldNotBe(entities[1]); - entities[0].ShouldNotBe(entities[2]); - entities[0].ShouldNotBe(entities[3]); - entities[0].ShouldNotBe(entities[4]); - entities[1].ShouldNotBe(entities[2]); - entities[1].ShouldNotBe(entities[3]); - entities[1].ShouldNotBe(entities[4]); - entities[2].ShouldNotBe(entities[3]); - entities[2].ShouldNotBe(entities[4]); - entities[3].ShouldNotBe(entities[4]); + List entities = Builder.CreateListOfSize(5); + + entities.ShouldBeUnique(); } [Fact] public void GivenListOfBuildersWithCustomisation_WhenBuildingEntitiesExplicitly_ThenTheCustomisationShouldTakeEffect() { var generator = new SequentialGenerator(0, 100); - var list = CustomerBuilder.CreateListOfSize(3) + var list = StudentViewModelBuilder.CreateListOfSize(3) .All().With(b => b.WithFirstName(generator.Generate().ToString())); var data = list.BuildList(); @@ -117,7 +102,7 @@ public void GivenListOfBuildersWithCustomisation_WhenBuildingEntitiesImplicitly_ { var generator = new SequentialGenerator(0, 100); - List data = CustomerBuilder.CreateListOfSize(3) + List data = StudentViewModelBuilder.CreateListOfSize(3) .All().With(b => b.WithFirstName(generator.Generate().ToString())); data.Select(c => c.FirstName).ToArray() @@ -128,67 +113,59 @@ public void GivenListOfBuildersWithCustomisation_WhenBuildingEntitiesImplicitly_ public void GivenListOfBuildersWithARangeOfCustomisationMethods_WhenBuildingEntitiesExplicitly_ThenThenTheListIsBuiltAndModifiedCorrectly() { var i = 0; - var customers = CustomerBuilder.CreateListOfSize(5) + var studentViewModels = StudentViewModelBuilder.CreateListOfSize(5) .TheFirst(1).WithFirstName("First") .TheNext(1).WithLastName("Next Last") .TheLast(1).WithLastName("Last Last") .ThePrevious(2).With(b => b.WithLastName("last" + (++i).ToString())) - .All().WhoJoinedIn(1999) + .All().WhoEntrolledIn(_enrollmentDate) .BuildList(); - customers.ShouldBeAssignableTo>(); - customers.Count.ShouldBe(5); - customers[0].FirstName.ShouldBe("First"); - customers[1].LastName.ShouldBe("Next Last"); - customers[2].LastName.ShouldBe("last1"); - customers[3].LastName.ShouldBe("last2"); - customers[4].LastName.ShouldBe("Last Last"); - customers.ShouldAllBe(c => c.YearJoined == 1999); + studentViewModels.ShouldBeAssignableTo>(); + studentViewModels.Count.ShouldBe(5); + studentViewModels[0].FirstName.ShouldBe("First"); + studentViewModels[1].LastName.ShouldBe("Next Last"); + studentViewModels[2].LastName.ShouldBe("last1"); + studentViewModels[3].LastName.ShouldBe("last2"); + studentViewModels[4].LastName.ShouldBe("Last Last"); + studentViewModels.ShouldAllBe(c => c.EnrollmentDate == _enrollmentDate); } [Fact] public void GivenListOfBuildersWithARangeOfCustomisationMethods_WhenBuildingEntitiesImplicitly_ThenThenTheListIsBuiltAndModifiedCorrectly() { var i = 0; - List customers = CustomerBuilder.CreateListOfSize(5) + List studentViewModels = StudentViewModelBuilder.CreateListOfSize(5) .TheFirst(1).WithFirstName("First") .TheNext(1).WithLastName("Next Last") .TheLast(1).WithLastName("Last Last") .ThePrevious(2).With(b => b.WithLastName("last" + (++i).ToString())) - .All().WhoJoinedIn(1999); - - customers.ShouldBeAssignableTo>(); - customers.Count.ShouldBe(5); - customers[0].FirstName.ShouldBe("First"); - customers[1].LastName.ShouldBe("Next Last"); - customers[2].LastName.ShouldBe("last1"); - customers[3].LastName.ShouldBe("last2"); - customers[4].LastName.ShouldBe("Last Last"); - customers.ShouldAllBe(c => c.YearJoined == 1999); + .All().WhoEntrolledIn(_enrollmentDate); + + studentViewModels.ShouldBeAssignableTo>(); + studentViewModels.Count.ShouldBe(5); + studentViewModels[0].FirstName.ShouldBe("First"); + studentViewModels[1].LastName.ShouldBe("Next Last"); + studentViewModels[2].LastName.ShouldBe("last1"); + studentViewModels[3].LastName.ShouldBe("last2"); + studentViewModels[4].LastName.ShouldBe("Last Last"); + studentViewModels.ShouldAllBe(c => c.EnrollmentDate == _enrollmentDate); } [Fact] public void WhenBuildingEntitiesExplicitly_ThenTheAnonymousValueFixtureIsSharedAcrossBuilders() { - var customers = CustomerBuilder.CreateListOfSize(5).BuildList(); + var studentViewModels = StudentViewModelBuilder.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); + studentViewModels.Select(x => x.Grade).ShouldBeUnique(); } [Fact] public void WhenBuildingEntitiesImplicitly_ThenTheAnonymousValueFixtureIsSharedAcrossBuilders() { - List customers = CustomerBuilder.CreateListOfSize(5); + List studentViewModels = StudentViewModelBuilder.CreateListOfSize(5); - 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); + studentViewModels.Select(x => x.Grade).ShouldBeUnique(); } } } \ No newline at end of file diff --git a/TestStack.Dossier.Tests/BuilderBuildTests.cs b/TestStack.Dossier.Tests/BuilderBuildTests.cs index 6b38f91..eb9829d 100644 --- a/TestStack.Dossier.Tests/BuilderBuildTests.cs +++ b/TestStack.Dossier.Tests/BuilderBuildTests.cs @@ -1,6 +1,7 @@ using Shouldly; using TestStack.Dossier.Tests.Builders; -using TestStack.Dossier.Tests.Entities; +using TestStack.Dossier.Tests.Stubs.Entities; +using TestStack.Dossier.Tests.Stubs.ViewModels; using Xunit; namespace TestStack.Dossier.Tests @@ -52,5 +53,18 @@ public void GivenBuilder_WhenCallingSetImplicitly_ShouldOverrideValues() customer.LastName.ShouldBe("Lanningham"); customer.YearJoined.ShouldBe(2014); } + + [Fact] + public void GivenBuilder_WhenBuildingObjectWithCtorAndPrivateSetters_ShouldSetPrivateSetters() + { + InstructorViewModel instructor = Builder.CreateNew() + .Set(x => x.FirstName, "Pi") + .Set(x => x.LastName, "Lanningham") + .Set(x => x.Id, 5); + + instructor.FirstName.ShouldBe("Pi"); + instructor.LastName.ShouldBe("Lanningham"); + instructor.Id.ShouldBe(5); + } } } \ No newline at end of file diff --git a/TestStack.Dossier.Tests/Builders/BasicCustomerBuilder.cs b/TestStack.Dossier.Tests/Builders/BasicCustomerBuilder.cs index df39128..dc6462f 100644 --- a/TestStack.Dossier.Tests/Builders/BasicCustomerBuilder.cs +++ b/TestStack.Dossier.Tests/Builders/BasicCustomerBuilder.cs @@ -1,6 +1,6 @@ using System; using System.Linq.Expressions; -using TestStack.Dossier.Tests.Entities; +using TestStack.Dossier.Tests.Stubs.Entities; namespace TestStack.Dossier.Tests.Builders { diff --git a/TestStack.Dossier.Tests/Builders/CustomerBuilder.cs b/TestStack.Dossier.Tests/Builders/CustomerBuilder.cs index 96e133c..319a57c 100644 --- a/TestStack.Dossier.Tests/Builders/CustomerBuilder.cs +++ b/TestStack.Dossier.Tests/Builders/CustomerBuilder.cs @@ -1,4 +1,4 @@ -using TestStack.Dossier.Tests.Entities; +using TestStack.Dossier.Tests.Stubs.Entities; namespace TestStack.Dossier.Tests.Builders { diff --git a/TestStack.Dossier.Tests/Builders/ProxyAlteringCustomerBuilder.cs b/TestStack.Dossier.Tests/Builders/ProxyAlteringCustomerBuilder.cs index 9272dd4..2419fdf 100644 --- a/TestStack.Dossier.Tests/Builders/ProxyAlteringCustomerBuilder.cs +++ b/TestStack.Dossier.Tests/Builders/ProxyAlteringCustomerBuilder.cs @@ -1,6 +1,6 @@ using System; using NSubstitute; -using TestStack.Dossier.Tests.Entities; +using TestStack.Dossier.Tests.Stubs.Entities; namespace TestStack.Dossier.Tests.Builders { diff --git a/TestStack.Dossier.Tests/Builders/StudentViewModelBuilder.cs b/TestStack.Dossier.Tests/Builders/StudentViewModelBuilder.cs new file mode 100644 index 0000000..9669a1d --- /dev/null +++ b/TestStack.Dossier.Tests/Builders/StudentViewModelBuilder.cs @@ -0,0 +1,23 @@ +using System; +using TestStack.Dossier.Tests.Stubs.ViewModels; + +namespace TestStack.Dossier.Tests.Builders +{ + public class StudentViewModelBuilder : TestDataBuilder + { + public virtual StudentViewModelBuilder WithFirstName(string firstName) + { + return Set(x => x.FirstName, firstName); + } + + public virtual StudentViewModelBuilder WithLastName(string lastName) + { + return Set(x => x.LastName, lastName); + } + + public virtual StudentViewModelBuilder WhoEntrolledIn(DateTime enrollmentDate) + { + return Set(x => x.EnrollmentDate, enrollmentDate); + } + } +} diff --git a/TestStack.Dossier.Tests/ProxyBuilderTests.cs b/TestStack.Dossier.Tests/ProxyBuilderTests.cs index e7aa540..ae9aef8 100644 --- a/TestStack.Dossier.Tests/ProxyBuilderTests.cs +++ b/TestStack.Dossier.Tests/ProxyBuilderTests.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using NSubstitute; using Shouldly; -using TestStack.Dossier.Tests.Entities; +using TestStack.Dossier.Tests.Stubs.Entities; using Xunit; namespace TestStack.Dossier.Tests diff --git a/TestStack.Dossier.Tests/Entities/Company.cs b/TestStack.Dossier.Tests/Stubs/Entities/Company.cs similarity index 86% rename from TestStack.Dossier.Tests/Entities/Company.cs rename to TestStack.Dossier.Tests/Stubs/Entities/Company.cs index 4e2dfbe..2635100 100644 --- a/TestStack.Dossier.Tests/Entities/Company.cs +++ b/TestStack.Dossier.Tests/Stubs/Entities/Company.cs @@ -1,4 +1,4 @@ -namespace TestStack.Dossier.Tests.Entities +namespace TestStack.Dossier.Tests.Stubs.Entities { public class Company { diff --git a/TestStack.Dossier.Tests/Entities/Customer.cs b/TestStack.Dossier.Tests/Stubs/Entities/Customer.cs similarity index 95% rename from TestStack.Dossier.Tests/Entities/Customer.cs rename to TestStack.Dossier.Tests/Stubs/Entities/Customer.cs index 5796b0d..0e71270 100644 --- a/TestStack.Dossier.Tests/Entities/Customer.cs +++ b/TestStack.Dossier.Tests/Stubs/Entities/Customer.cs @@ -1,6 +1,6 @@ -using System; +using System; -namespace TestStack.Dossier.Tests.Entities +namespace TestStack.Dossier.Tests.Stubs.Entities { public class Customer { diff --git a/TestStack.Dossier.Tests/Entities/CustomerClass.cs b/TestStack.Dossier.Tests/Stubs/Entities/CustomerClass.cs similarity index 70% rename from TestStack.Dossier.Tests/Entities/CustomerClass.cs rename to TestStack.Dossier.Tests/Stubs/Entities/CustomerClass.cs index 81f3956..dd79d7b 100644 --- a/TestStack.Dossier.Tests/Entities/CustomerClass.cs +++ b/TestStack.Dossier.Tests/Stubs/Entities/CustomerClass.cs @@ -1,4 +1,4 @@ -namespace TestStack.Dossier.Tests.Entities +namespace TestStack.Dossier.Tests.Stubs.Entities { public enum CustomerClass { diff --git a/TestStack.Dossier.Tests/Stubs/ViewModels/Grade.cs b/TestStack.Dossier.Tests/Stubs/ViewModels/Grade.cs new file mode 100644 index 0000000..8598bb2 --- /dev/null +++ b/TestStack.Dossier.Tests/Stubs/ViewModels/Grade.cs @@ -0,0 +1,7 @@ +namespace TestStack.Dossier.Tests.Stubs.ViewModels +{ + public enum Grade + { + A, B, C, D, F + } +} \ No newline at end of file diff --git a/TestStack.Dossier.Tests/Stubs/ViewModels/InstructorViewModel.cs b/TestStack.Dossier.Tests/Stubs/ViewModels/InstructorViewModel.cs new file mode 100644 index 0000000..44866e0 --- /dev/null +++ b/TestStack.Dossier.Tests/Stubs/ViewModels/InstructorViewModel.cs @@ -0,0 +1,30 @@ +using System; + +namespace TestStack.Dossier.Tests.Stubs.ViewModels +{ + public class InstructorViewModel + { + public InstructorViewModel(int id, string firstName, string lastName) + { + Id = id; + FirstName = firstName; + LastName = lastName; + } + + public int Id { get; private set; } + + public string LastName { get; private set; } + public string FirstName { get; private set; } + + public string FullName + { + get + { + return FirstName + " " + LastName; + } + } + public DateTime JoinDate { get; set; } + + public Grade Grade { get; set; } + } +} diff --git a/TestStack.Dossier.Tests/Stubs/ViewModels/StudentViewModel.cs b/TestStack.Dossier.Tests/Stubs/ViewModels/StudentViewModel.cs new file mode 100644 index 0000000..674a844 --- /dev/null +++ b/TestStack.Dossier.Tests/Stubs/ViewModels/StudentViewModel.cs @@ -0,0 +1,35 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace TestStack.Dossier.Tests.Stubs.ViewModels +{ + public class StudentViewModel + { + public int Id { get; set; } + + [Required] + [StringLength(50)] + [Display(Name = "Last Name")] + public string LastName { get; set; } + [Required] + [StringLength(50, ErrorMessage = "First name cannot be longer than 50 characters.")] + [Display(Name = "First Name")] + public string FirstName { get; set; } + + [Display(Name = "Full Name")] + public string FullName + { + get + { + return FirstName + " " + LastName; + } + } + + [DataType(DataType.Date)] + [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)] + [Display(Name = "Enrollment Date")] + public DateTime EnrollmentDate { get; set; } + + public Grade Grade { get; set; } + } +} diff --git a/TestStack.Dossier.Tests/TestStack.Dossier.Tests.csproj b/TestStack.Dossier.Tests/TestStack.Dossier.Tests.csproj index 0b2c2b0..43d79d9 100644 --- a/TestStack.Dossier.Tests/TestStack.Dossier.Tests.csproj +++ b/TestStack.Dossier.Tests/TestStack.Dossier.Tests.csproj @@ -44,6 +44,7 @@ ..\packages\Shouldly.2.4.0\lib\net40\Shouldly.dll + @@ -56,8 +57,11 @@ + - + + + @@ -77,13 +81,14 @@ - - + + + diff --git a/TestStack.Dossier/AnonymousValueFixture.cs b/TestStack.Dossier/AnonymousValueFixture.cs index 0d26193..9402247 100644 --- a/TestStack.Dossier/AnonymousValueFixture.cs +++ b/TestStack.Dossier/AnonymousValueFixture.cs @@ -82,7 +82,7 @@ public AnonymousValueFixture() /// The anonymous value, taking into account any registered conventions public T Get(Expression> property) { - var propertyName = Reflector.GetPropertyFor(property); + var propertyName = Reflector.GetPropertyNameFor(property); var valueSupplier = LocalValueSuppliers .Concat(GlobalValueSuppliers) .Concat(DefaultValueSuppliers) diff --git a/TestStack.Dossier/Reflector.cs b/TestStack.Dossier/Reflector.cs index bd6c5c6..5e3f51c 100644 --- a/TestStack.Dossier/Reflector.cs +++ b/TestStack.Dossier/Reflector.cs @@ -6,7 +6,7 @@ namespace TestStack.Dossier { internal static class Reflector { - public static string GetPropertyFor(Expression> property) + public static string GetPropertyNameFor(Expression> property) { var memExp = property.Body as MemberExpression; if (memExp == null) diff --git a/TestStack.Dossier/TestDataBuilder.cs b/TestStack.Dossier/TestDataBuilder.cs index 00ec434..5c93d42 100644 --- a/TestStack.Dossier/TestDataBuilder.cs +++ b/TestStack.Dossier/TestDataBuilder.cs @@ -82,8 +82,11 @@ protected virtual TObject BuildObject() var properties = Reflector.GetSettablePropertiesFor(); foreach (var property in properties) { - var val = Get(property.PropertyType, property.Name); - property.SetValue(model, val, null); + if (property.CanWrite) + { + var val = Get(property.PropertyType, property.Name); + property.SetValue(model, val, null); + } } return model; @@ -114,7 +117,7 @@ protected virtual void AlterProxy(TObject proxy) {} /// The value to record public TBuilder Set(Expression> property, TValue value) { - _properties[Reflector.GetPropertyFor(property)] = value; + _properties[Reflector.GetPropertyNameFor(property)] = value; return this as TBuilder; } @@ -130,7 +133,7 @@ public TValue Get(Expression> property) if (!Has(property)) return Any.Get(property); - return (TValue)_properties[Reflector.GetPropertyFor(property)]; + return (TValue)_properties[Reflector.GetPropertyNameFor(property)]; } public object Get(Type type, string propertyName) @@ -174,7 +177,7 @@ public static ListBuilder CreateListOfSize(int size) /// Whether or not there is a recorded value for the property protected bool Has(Expression> property) { - return Has(Reflector.GetPropertyFor(property)); + return Has(Reflector.GetPropertyNameFor(property)); } /// From 4f9539957d3a25e458d99654bf1bec71664e856e Mon Sep 17 00:00:00 2001 From: Michael Whelan Date: Fri, 1 May 2015 17:59:31 +0100 Subject: [PATCH 05/10] Introduced Object Builders I managed to break ConstructorBuilder when I moved it from TestDataBuilder --- .../AutoConstructorCustomerBuilder.cs | 5 +- .../AllPropertiesObjectBuilder.cs | 30 ++++++++ .../AutoFixtureObjectBuilder.cs | 18 +++++ .../ConstructorObjectBuilder.cs | 56 +++++++++++++++ .../ObjectBuilders/FactoryRegistry.cs | 32 +++++++++ .../ObjectBuilders/IObjectBuilder.cs | 19 +++++ .../PublicPropertiesObjectBuilder.cs | 30 ++++++++ TestStack.Dossier/TestDataBuilder.cs | 70 ++++--------------- TestStack.Dossier/TestStack.Dossier.csproj | 6 ++ 9 files changed, 206 insertions(+), 60 deletions(-) create mode 100644 TestStack.Dossier/ObjectBuilders/AllPropertiesObjectBuilder.cs create mode 100644 TestStack.Dossier/ObjectBuilders/AutoFixtureObjectBuilder.cs create mode 100644 TestStack.Dossier/ObjectBuilders/ConstructorObjectBuilder.cs create mode 100644 TestStack.Dossier/ObjectBuilders/FactoryRegistry.cs create mode 100644 TestStack.Dossier/ObjectBuilders/IObjectBuilder.cs create mode 100644 TestStack.Dossier/ObjectBuilders/PublicPropertiesObjectBuilder.cs diff --git a/TestStack.Dossier.Tests/Builders/AutoConstructorCustomerBuilder.cs b/TestStack.Dossier.Tests/Builders/AutoConstructorCustomerBuilder.cs index b699509..0513783 100644 --- a/TestStack.Dossier.Tests/Builders/AutoConstructorCustomerBuilder.cs +++ b/TestStack.Dossier.Tests/Builders/AutoConstructorCustomerBuilder.cs @@ -1,4 +1,5 @@ -using TestStack.Dossier.Tests.Stubs.Entities; +using TestStack.Dossier.ObjectBuilders; +using TestStack.Dossier.Tests.Stubs.Entities; namespace TestStack.Dossier.Tests.Builders { @@ -6,7 +7,7 @@ class AutoConstructorCustomerBuilder : TestDataBuilder().BuildObject(this); } public AutoConstructorCustomerBuilder WithFirstName(string firstName) diff --git a/TestStack.Dossier/ObjectBuilders/AllPropertiesObjectBuilder.cs b/TestStack.Dossier/ObjectBuilders/AllPropertiesObjectBuilder.cs new file mode 100644 index 0000000..103be21 --- /dev/null +++ b/TestStack.Dossier/ObjectBuilders/AllPropertiesObjectBuilder.cs @@ -0,0 +1,30 @@ +using Ploeh.AutoFixture; + +namespace TestStack.Dossier.ObjectBuilders +{ + /// + /// Creates an instance of an object by setting all public and private properties. + /// + public class AllPropertiesObjectBuilder : IObjectBuilder + { + /// + public TObject BuildObject(TestDataBuilder builder) + where TObject : class + where TBuilder : TestDataBuilder, new() + { + var model = builder.Any.Fixture.Create(); + + var properties = Reflector.GetSettablePropertiesFor(); + foreach (var property in properties) + { + if (property.CanWrite) + { + var val = builder.Get(property.PropertyType, property.Name); + property.SetValue(model, val, null); + } + } + + return model; + } + } +} \ No newline at end of file diff --git a/TestStack.Dossier/ObjectBuilders/AutoFixtureObjectBuilder.cs b/TestStack.Dossier/ObjectBuilders/AutoFixtureObjectBuilder.cs new file mode 100644 index 0000000..1456486 --- /dev/null +++ b/TestStack.Dossier/ObjectBuilders/AutoFixtureObjectBuilder.cs @@ -0,0 +1,18 @@ +using Ploeh.AutoFixture; + +namespace TestStack.Dossier.ObjectBuilders +{ + /// + /// Creates an instance of an object with AutoFixture. + /// + public class AutoFixtureObjectBuilder : IObjectBuilder + { + /// + public TObject BuildObject(TestDataBuilder builder) + where TObject : class + where TBuilder : TestDataBuilder, new() + { + return builder.Any.Fixture.Create(); + } + } +} \ No newline at end of file diff --git a/TestStack.Dossier/ObjectBuilders/ConstructorObjectBuilder.cs b/TestStack.Dossier/ObjectBuilders/ConstructorObjectBuilder.cs new file mode 100644 index 0000000..a23c9ca --- /dev/null +++ b/TestStack.Dossier/ObjectBuilders/ConstructorObjectBuilder.cs @@ -0,0 +1,56 @@ +using System; +using System.Linq; +using System.Linq.Expressions; +using Ploeh.AutoFixture; + +namespace TestStack.Dossier.ObjectBuilders +{ + /// + /// Builds the object using the constructor with the most arguments. + /// + public class ConstructorObjectBuilder : IObjectBuilder + { + /// + public TObject BuildObject(TestDataBuilder builder) + where TObject : class + where TBuilder : TestDataBuilder, new() + { + var longestConstructor = typeof(TObject) + .GetConstructors() + .OrderByDescending(x => x.GetParameters().Length) + .FirstOrDefault(); + + if (longestConstructor == null) throw new ObjectCreationException(); + + var parameterValues = longestConstructor + .GetParameters() + .Select(x => CallGetWithType(x.Name, x.ParameterType, typeof(TObject), typeof(TBuilder))); + + return (TObject)longestConstructor.Invoke(parameterValues.ToArray()); + } + + private object CallGetWithType(string propertyName, Type propertyType, Type objectType, Type builderType) + { + // Make a Func + var expressionDelegateType = typeof(Func<,>).MakeGenericType(objectType, propertyType); + + // Make an expression parameter of type TObj + var tObjParameterType = Expression.Parameter(objectType); + + var valueStoredInBuilder = builderType + .GetMethods() + .First(method => method.Name == "Get" && method.ContainsGenericParameters && method.GetGenericArguments().Length == 1) + .MakeGenericMethod(propertyType) + .Invoke(this, new object[] + { + Expression.Lambda( + expressionDelegateType, + Expression.Property(tObjParameterType, propertyName), + tObjParameterType) + }); + + return valueStoredInBuilder; + } + + } +} \ No newline at end of file diff --git a/TestStack.Dossier/ObjectBuilders/FactoryRegistry.cs b/TestStack.Dossier/ObjectBuilders/FactoryRegistry.cs new file mode 100644 index 0000000..6dc54be --- /dev/null +++ b/TestStack.Dossier/ObjectBuilders/FactoryRegistry.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace TestStack.Dossier.ObjectBuilders +{ + /// + /// A static registry of object builder factories. + /// + public static class FactoryRegistry + { + private static List> _factories = new List> + { + new Tuple(typeof(AllPropertiesObjectBuilder), new AllPropertiesObjectBuilder()), + new Tuple(typeof(PublicPropertiesObjectBuilder), new PublicPropertiesObjectBuilder()), + new Tuple(typeof(ConstructorObjectBuilder), new ConstructorObjectBuilder()), + new Tuple(typeof(AutoFixtureObjectBuilder), new AutoFixtureObjectBuilder()) + }; + + /// + /// Provides access to specified factory. + /// + /// + /// The requested Factory + public static IObjectBuilder Get() where T : IObjectBuilder + { + return _factories.Where(x => x.Item1 == typeof (T)) + .Select(x => x.Item2) + .First(); + } + } +} \ No newline at end of file diff --git a/TestStack.Dossier/ObjectBuilders/IObjectBuilder.cs b/TestStack.Dossier/ObjectBuilders/IObjectBuilder.cs new file mode 100644 index 0000000..3f52c40 --- /dev/null +++ b/TestStack.Dossier/ObjectBuilders/IObjectBuilder.cs @@ -0,0 +1,19 @@ +namespace TestStack.Dossier.ObjectBuilders +{ + /// + /// Interface for object building strategies + /// + public interface IObjectBuilder + { + /// + /// Takes a builder and generates an object of the specified type. + /// + /// An instance of the TestDataBuilder. + /// The generic type of the object that will be generated. + /// The generic type of the TestDataBuilder. + /// An instance of the created object. + TObject BuildObject(TestDataBuilder builder) + where TObject : class + where TBuilder : TestDataBuilder, new(); + } +} \ No newline at end of file diff --git a/TestStack.Dossier/ObjectBuilders/PublicPropertiesObjectBuilder.cs b/TestStack.Dossier/ObjectBuilders/PublicPropertiesObjectBuilder.cs new file mode 100644 index 0000000..2545c97 --- /dev/null +++ b/TestStack.Dossier/ObjectBuilders/PublicPropertiesObjectBuilder.cs @@ -0,0 +1,30 @@ +using Ploeh.AutoFixture; + +namespace TestStack.Dossier.ObjectBuilders +{ + /// + /// Creates an instance of an object by setting all public properties but not private properties. + /// + public class PublicPropertiesObjectBuilder : IObjectBuilder + { + /// + public TObject BuildObject(TestDataBuilder builder) + where TObject : class + where TBuilder : TestDataBuilder, new() + { + var model = builder.Any.Fixture.Create(); + + var properties = Reflector.GetSettablePropertiesFor(); + foreach (var property in properties) + { + if (property.CanWrite && property.GetSetMethod().IsPublic) + { + var val = builder.Get(property.PropertyType, property.Name); + property.SetValue(model, val, null); + } + } + + return model; + } + } +} \ No newline at end of file diff --git a/TestStack.Dossier/TestDataBuilder.cs b/TestStack.Dossier/TestDataBuilder.cs index 2eb9210..6a661ba 100644 --- a/TestStack.Dossier/TestDataBuilder.cs +++ b/TestStack.Dossier/TestDataBuilder.cs @@ -1,10 +1,8 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Linq.Expressions; -using System.Reflection; -using Ploeh.AutoFixture; using TestStack.Dossier.Lists; +using TestStack.Dossier.ObjectBuilders; namespace TestStack.Dossier { @@ -78,17 +76,9 @@ public static implicit operator List(TestDataBuilder /// The built object protected virtual TObject BuildObject() { - var model = Any.Fixture.Create(); - - var properties = Reflector.GetSettablePropertiesFor(); - foreach (var property in properties) - { - if (property.CanWrite) - { - var val = Get(property.PropertyType, property.Name); - property.SetValue(model, val, null); - } - } + var model = FactoryRegistry + .Get() + .BuildObject(this); return model; } @@ -126,7 +116,7 @@ public TBuilder Set(Expression> property, TValue v /// Gets the recorded value for the given property from {TObject} or an anonymous /// value if there isn't one specified. /// - /// The type of the property + /// The type of the property. /// A lambda expression specifying the property to retrieve the recorded value for /// The recorded value of the property or an anonymous value for it public TValue Get(Expression> property) @@ -137,6 +127,13 @@ public TValue Get(Expression> property) return (TValue)_properties[Reflector.GetPropertyNameFor(property)]; } + /// + /// Gets the recorded value for the given property from {type} or an anonymous + /// value if there isn't one specified. + /// + /// The type of the property. + /// The property name. + /// public object Get(Type type, string propertyName) { if (!Has(propertyName)) @@ -216,48 +213,5 @@ protected virtual TChildBuilder GetChildBuilder(Fun modifier(childBuilder); return childBuilder; } - - /// - /// Builds the object using the constructor with the most arguments. - /// - /// - protected virtual TObject BuildByConstructor() - { - var longestConstructor = typeof (TObject) - .GetConstructors() - .OrderByDescending(x => x.GetParameters().Length) - .FirstOrDefault(); - - if (longestConstructor == null) throw new ObjectCreationException(); - - var parameterValues = longestConstructor - .GetParameters() - .Select(x => CallGetWithType(x.Name, x.ParameterType)); - - return (TObject) longestConstructor.Invoke(parameterValues.ToArray()); - } - - private object CallGetWithType(string propertyName, Type propertyType) - { - // Make a Func - var expressionDelegateType = typeof(Func<,>).MakeGenericType(typeof(TObject), propertyType); - - // Make an expression parameter of type TObj - var tObjParameterType = Expression.Parameter(typeof(TObject)); - - var valueStoredInBuilder = typeof(TBuilder) - .GetMethods() - .First(method => method.Name == "Get" && method.ContainsGenericParameters && method.GetGenericArguments().Length ==1) - .MakeGenericMethod(propertyType) - .Invoke(this, new object[] - { - Expression.Lambda( - expressionDelegateType, - Expression.Property(tObjParameterType, propertyName), - tObjParameterType) - }); - - return valueStoredInBuilder; - } } } diff --git a/TestStack.Dossier/TestStack.Dossier.csproj b/TestStack.Dossier/TestStack.Dossier.csproj index c7f8187..85c34aa 100644 --- a/TestStack.Dossier/TestStack.Dossier.csproj +++ b/TestStack.Dossier/TestStack.Dossier.csproj @@ -80,6 +80,11 @@ + + + + + @@ -87,6 +92,7 @@ + From c0c8dbebd631898bbf83dcf7cfe04ecb222bb9cd Mon Sep 17 00:00:00 2001 From: Michael Whelan Date: Fri, 1 May 2015 18:07:44 +0100 Subject: [PATCH 06/10] Renamed FactoryRegistry to ObjectBuilderRegistry --- .../Builders/AutoConstructorCustomerBuilder.cs | 2 +- .../{FactoryRegistry.cs => ObjectBuilderRegistry.cs} | 2 +- TestStack.Dossier/TestDataBuilder.cs | 2 +- TestStack.Dossier/TestStack.Dossier.csproj | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename TestStack.Dossier/ObjectBuilders/{FactoryRegistry.cs => ObjectBuilderRegistry.cs} (96%) diff --git a/TestStack.Dossier.Tests/Builders/AutoConstructorCustomerBuilder.cs b/TestStack.Dossier.Tests/Builders/AutoConstructorCustomerBuilder.cs index 0513783..d424392 100644 --- a/TestStack.Dossier.Tests/Builders/AutoConstructorCustomerBuilder.cs +++ b/TestStack.Dossier.Tests/Builders/AutoConstructorCustomerBuilder.cs @@ -7,7 +7,7 @@ class AutoConstructorCustomerBuilder : TestDataBuilder().BuildObject(this); + return ObjectBuilderRegistry.Get().BuildObject(this); } public AutoConstructorCustomerBuilder WithFirstName(string firstName) diff --git a/TestStack.Dossier/ObjectBuilders/FactoryRegistry.cs b/TestStack.Dossier/ObjectBuilders/ObjectBuilderRegistry.cs similarity index 96% rename from TestStack.Dossier/ObjectBuilders/FactoryRegistry.cs rename to TestStack.Dossier/ObjectBuilders/ObjectBuilderRegistry.cs index 6dc54be..2b7c617 100644 --- a/TestStack.Dossier/ObjectBuilders/FactoryRegistry.cs +++ b/TestStack.Dossier/ObjectBuilders/ObjectBuilderRegistry.cs @@ -7,7 +7,7 @@ namespace TestStack.Dossier.ObjectBuilders /// /// A static registry of object builder factories. /// - public static class FactoryRegistry + public static class ObjectBuilderRegistry { private static List> _factories = new List> { diff --git a/TestStack.Dossier/TestDataBuilder.cs b/TestStack.Dossier/TestDataBuilder.cs index 6a661ba..3b9ee04 100644 --- a/TestStack.Dossier/TestDataBuilder.cs +++ b/TestStack.Dossier/TestDataBuilder.cs @@ -76,7 +76,7 @@ public static implicit operator List(TestDataBuilder /// The built object protected virtual TObject BuildObject() { - var model = FactoryRegistry + var model = ObjectBuilderRegistry .Get() .BuildObject(this); diff --git a/TestStack.Dossier/TestStack.Dossier.csproj b/TestStack.Dossier/TestStack.Dossier.csproj index 85c34aa..3b55622 100644 --- a/TestStack.Dossier/TestStack.Dossier.csproj +++ b/TestStack.Dossier/TestStack.Dossier.csproj @@ -82,7 +82,7 @@ - + From a2602a6e093cc7cf16bc38defd78afe2f0242282 Mon Sep 17 00:00:00 2001 From: Michael Whelan Date: Fri, 1 May 2015 18:40:23 +0100 Subject: [PATCH 07/10] Renamed object builders to strategies --- .../AutoConstructorCustomerBuilder.cs | 4 +-- .../AllProperties.cs} | 4 +-- .../AutoFixture.cs} | 4 +-- .../BuildStrategies/BuilderStrategy.cs | 32 +++++++++++++++++++ .../IBuildStrategy.cs} | 4 +-- .../PublicProperties.cs} | 4 +-- .../UseConstructor.cs} | 4 +-- .../ObjectBuilders/ObjectBuilderRegistry.cs | 32 ------------------- TestStack.Dossier/TestDataBuilder.cs | 6 ++-- TestStack.Dossier/TestStack.Dossier.csproj | 12 +++---- 10 files changed, 53 insertions(+), 53 deletions(-) rename TestStack.Dossier/{ObjectBuilders/AllPropertiesObjectBuilder.cs => BuildStrategies/AllProperties.cs} (89%) rename TestStack.Dossier/{ObjectBuilders/AutoFixtureObjectBuilder.cs => BuildStrategies/AutoFixture.cs} (81%) create mode 100644 TestStack.Dossier/BuildStrategies/BuilderStrategy.cs rename TestStack.Dossier/{ObjectBuilders/IObjectBuilder.cs => BuildStrategies/IBuildStrategy.cs} (90%) rename TestStack.Dossier/{ObjectBuilders/PublicPropertiesObjectBuilder.cs => BuildStrategies/PublicProperties.cs} (89%) rename TestStack.Dossier/{ObjectBuilders/ConstructorObjectBuilder.cs => BuildStrategies/UseConstructor.cs} (95%) delete mode 100644 TestStack.Dossier/ObjectBuilders/ObjectBuilderRegistry.cs diff --git a/TestStack.Dossier.Tests/Builders/AutoConstructorCustomerBuilder.cs b/TestStack.Dossier.Tests/Builders/AutoConstructorCustomerBuilder.cs index d424392..0800f07 100644 --- a/TestStack.Dossier.Tests/Builders/AutoConstructorCustomerBuilder.cs +++ b/TestStack.Dossier.Tests/Builders/AutoConstructorCustomerBuilder.cs @@ -1,4 +1,4 @@ -using TestStack.Dossier.ObjectBuilders; +using TestStack.Dossier.BuildStrategies; using TestStack.Dossier.Tests.Stubs.Entities; namespace TestStack.Dossier.Tests.Builders @@ -7,7 +7,7 @@ class AutoConstructorCustomerBuilder : TestDataBuilder().BuildObject(this); + return BuilderStrategy.Apply().BuildObject(this); } public AutoConstructorCustomerBuilder WithFirstName(string firstName) diff --git a/TestStack.Dossier/ObjectBuilders/AllPropertiesObjectBuilder.cs b/TestStack.Dossier/BuildStrategies/AllProperties.cs similarity index 89% rename from TestStack.Dossier/ObjectBuilders/AllPropertiesObjectBuilder.cs rename to TestStack.Dossier/BuildStrategies/AllProperties.cs index 103be21..75c18fb 100644 --- a/TestStack.Dossier/ObjectBuilders/AllPropertiesObjectBuilder.cs +++ b/TestStack.Dossier/BuildStrategies/AllProperties.cs @@ -1,11 +1,11 @@ using Ploeh.AutoFixture; -namespace TestStack.Dossier.ObjectBuilders +namespace TestStack.Dossier.BuildStrategies { /// /// Creates an instance of an object by setting all public and private properties. /// - public class AllPropertiesObjectBuilder : IObjectBuilder + public class AllProperties : IBuildStrategy { /// public TObject BuildObject(TestDataBuilder builder) diff --git a/TestStack.Dossier/ObjectBuilders/AutoFixtureObjectBuilder.cs b/TestStack.Dossier/BuildStrategies/AutoFixture.cs similarity index 81% rename from TestStack.Dossier/ObjectBuilders/AutoFixtureObjectBuilder.cs rename to TestStack.Dossier/BuildStrategies/AutoFixture.cs index 1456486..56922a0 100644 --- a/TestStack.Dossier/ObjectBuilders/AutoFixtureObjectBuilder.cs +++ b/TestStack.Dossier/BuildStrategies/AutoFixture.cs @@ -1,11 +1,11 @@ using Ploeh.AutoFixture; -namespace TestStack.Dossier.ObjectBuilders +namespace TestStack.Dossier.BuildStrategies { /// /// Creates an instance of an object with AutoFixture. /// - public class AutoFixtureObjectBuilder : IObjectBuilder + public class AutoFixture : IBuildStrategy { /// public TObject BuildObject(TestDataBuilder builder) diff --git a/TestStack.Dossier/BuildStrategies/BuilderStrategy.cs b/TestStack.Dossier/BuildStrategies/BuilderStrategy.cs new file mode 100644 index 0000000..3676c57 --- /dev/null +++ b/TestStack.Dossier/BuildStrategies/BuilderStrategy.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace TestStack.Dossier.BuildStrategies +{ + /// + /// A static registry of object builder factories. + /// + public static class BuilderStrategy + { + private static List> _factories = new List> + { + new Tuple(typeof(AllProperties), new AllProperties()), + new Tuple(typeof(PublicProperties), new PublicProperties()), + new Tuple(typeof(UseConstructor), new UseConstructor()), + new Tuple(typeof(AutoFixture), new AutoFixture()) + }; + + /// + /// Provides access to specified factory. + /// + /// + /// The requested Factory + public static IBuildStrategy Apply() where T : IBuildStrategy + { + return _factories.Where(x => x.Item1 == typeof (T)) + .Select(x => x.Item2) + .First(); + } + } +} \ No newline at end of file diff --git a/TestStack.Dossier/ObjectBuilders/IObjectBuilder.cs b/TestStack.Dossier/BuildStrategies/IBuildStrategy.cs similarity index 90% rename from TestStack.Dossier/ObjectBuilders/IObjectBuilder.cs rename to TestStack.Dossier/BuildStrategies/IBuildStrategy.cs index 3f52c40..d9b9cac 100644 --- a/TestStack.Dossier/ObjectBuilders/IObjectBuilder.cs +++ b/TestStack.Dossier/BuildStrategies/IBuildStrategy.cs @@ -1,9 +1,9 @@ -namespace TestStack.Dossier.ObjectBuilders +namespace TestStack.Dossier.BuildStrategies { /// /// Interface for object building strategies /// - public interface IObjectBuilder + public interface IBuildStrategy { /// /// Takes a builder and generates an object of the specified type. diff --git a/TestStack.Dossier/ObjectBuilders/PublicPropertiesObjectBuilder.cs b/TestStack.Dossier/BuildStrategies/PublicProperties.cs similarity index 89% rename from TestStack.Dossier/ObjectBuilders/PublicPropertiesObjectBuilder.cs rename to TestStack.Dossier/BuildStrategies/PublicProperties.cs index 2545c97..c1ff0fc 100644 --- a/TestStack.Dossier/ObjectBuilders/PublicPropertiesObjectBuilder.cs +++ b/TestStack.Dossier/BuildStrategies/PublicProperties.cs @@ -1,11 +1,11 @@ using Ploeh.AutoFixture; -namespace TestStack.Dossier.ObjectBuilders +namespace TestStack.Dossier.BuildStrategies { /// /// Creates an instance of an object by setting all public properties but not private properties. /// - public class PublicPropertiesObjectBuilder : IObjectBuilder + public class PublicProperties : IBuildStrategy { /// public TObject BuildObject(TestDataBuilder builder) diff --git a/TestStack.Dossier/ObjectBuilders/ConstructorObjectBuilder.cs b/TestStack.Dossier/BuildStrategies/UseConstructor.cs similarity index 95% rename from TestStack.Dossier/ObjectBuilders/ConstructorObjectBuilder.cs rename to TestStack.Dossier/BuildStrategies/UseConstructor.cs index a23c9ca..cc1cd5d 100644 --- a/TestStack.Dossier/ObjectBuilders/ConstructorObjectBuilder.cs +++ b/TestStack.Dossier/BuildStrategies/UseConstructor.cs @@ -3,12 +3,12 @@ using System.Linq.Expressions; using Ploeh.AutoFixture; -namespace TestStack.Dossier.ObjectBuilders +namespace TestStack.Dossier.BuildStrategies { /// /// Builds the object using the constructor with the most arguments. /// - public class ConstructorObjectBuilder : IObjectBuilder + public class UseConstructor : IBuildStrategy { /// public TObject BuildObject(TestDataBuilder builder) diff --git a/TestStack.Dossier/ObjectBuilders/ObjectBuilderRegistry.cs b/TestStack.Dossier/ObjectBuilders/ObjectBuilderRegistry.cs deleted file mode 100644 index 2b7c617..0000000 --- a/TestStack.Dossier/ObjectBuilders/ObjectBuilderRegistry.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace TestStack.Dossier.ObjectBuilders -{ - /// - /// A static registry of object builder factories. - /// - public static class ObjectBuilderRegistry - { - private static List> _factories = new List> - { - new Tuple(typeof(AllPropertiesObjectBuilder), new AllPropertiesObjectBuilder()), - new Tuple(typeof(PublicPropertiesObjectBuilder), new PublicPropertiesObjectBuilder()), - new Tuple(typeof(ConstructorObjectBuilder), new ConstructorObjectBuilder()), - new Tuple(typeof(AutoFixtureObjectBuilder), new AutoFixtureObjectBuilder()) - }; - - /// - /// Provides access to specified factory. - /// - /// - /// The requested Factory - public static IObjectBuilder Get() where T : IObjectBuilder - { - return _factories.Where(x => x.Item1 == typeof (T)) - .Select(x => x.Item2) - .First(); - } - } -} \ No newline at end of file diff --git a/TestStack.Dossier/TestDataBuilder.cs b/TestStack.Dossier/TestDataBuilder.cs index 3b9ee04..0945737 100644 --- a/TestStack.Dossier/TestDataBuilder.cs +++ b/TestStack.Dossier/TestDataBuilder.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.Linq.Expressions; +using TestStack.Dossier.BuildStrategies; using TestStack.Dossier.Lists; -using TestStack.Dossier.ObjectBuilders; namespace TestStack.Dossier { @@ -76,8 +76,8 @@ public static implicit operator List(TestDataBuilder /// The built object protected virtual TObject BuildObject() { - var model = ObjectBuilderRegistry - .Get() + var model = BuilderStrategy + .Apply() .BuildObject(this); return model; diff --git a/TestStack.Dossier/TestStack.Dossier.csproj b/TestStack.Dossier/TestStack.Dossier.csproj index 3b55622..2c48472 100644 --- a/TestStack.Dossier/TestStack.Dossier.csproj +++ b/TestStack.Dossier/TestStack.Dossier.csproj @@ -80,11 +80,11 @@ - - - - - + + + + + @@ -92,7 +92,7 @@ - + From 8f0dc5f53da58ca34d54fe4a7d51b5d7828643b1 Mon Sep 17 00:00:00 2001 From: Michael Whelan Date: Sun, 3 May 2015 10:06:35 +0100 Subject: [PATCH 08/10] Settled on object builder design --- .../AutoConstructorCustomerBuilder.cs | 8 ++--- .../BuildStrategies/BuilderStrategy.cs | 32 ------------------- TestStack.Dossier/Builder.cs | 12 +++++-- .../AllPropertiesFactory.cs} | 4 +-- .../AutoFixtureFactory.cs} | 4 +-- .../ConstructorFactory.cs} | 23 +++++++------ .../IFactory.cs} | 4 +-- .../PublicPropertiesFactory.cs} | 4 +-- TestStack.Dossier/IAnonymousValueSupplier.cs | 3 +- TestStack.Dossier/TestDataBuilder.cs | 16 +++++++--- TestStack.Dossier/TestStack.Dossier.csproj | 11 +++---- 11 files changed, 51 insertions(+), 70 deletions(-) delete mode 100644 TestStack.Dossier/BuildStrategies/BuilderStrategy.cs rename TestStack.Dossier/{BuildStrategies/AllProperties.cs => Factories/AllPropertiesFactory.cs} (90%) rename TestStack.Dossier/{BuildStrategies/AutoFixture.cs => Factories/AutoFixtureFactory.cs} (83%) rename TestStack.Dossier/{BuildStrategies/UseConstructor.cs => Factories/ConstructorFactory.cs} (66%) rename TestStack.Dossier/{BuildStrategies/IBuildStrategy.cs => Factories/IFactory.cs} (90%) rename TestStack.Dossier/{BuildStrategies/PublicProperties.cs => Factories/PublicPropertiesFactory.cs} (90%) diff --git a/TestStack.Dossier.Tests/Builders/AutoConstructorCustomerBuilder.cs b/TestStack.Dossier.Tests/Builders/AutoConstructorCustomerBuilder.cs index 0800f07..70668ac 100644 --- a/TestStack.Dossier.Tests/Builders/AutoConstructorCustomerBuilder.cs +++ b/TestStack.Dossier.Tests/Builders/AutoConstructorCustomerBuilder.cs @@ -1,14 +1,12 @@ -using TestStack.Dossier.BuildStrategies; +using TestStack.Dossier.Factories; using TestStack.Dossier.Tests.Stubs.Entities; namespace TestStack.Dossier.Tests.Builders { class AutoConstructorCustomerBuilder : TestDataBuilder { - protected override Customer BuildObject() - { - return BuilderStrategy.Apply().BuildObject(this); - } + public AutoConstructorCustomerBuilder() + : base(new ConstructorFactory()) { } public AutoConstructorCustomerBuilder WithFirstName(string firstName) { diff --git a/TestStack.Dossier/BuildStrategies/BuilderStrategy.cs b/TestStack.Dossier/BuildStrategies/BuilderStrategy.cs deleted file mode 100644 index 3676c57..0000000 --- a/TestStack.Dossier/BuildStrategies/BuilderStrategy.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace TestStack.Dossier.BuildStrategies -{ - /// - /// A static registry of object builder factories. - /// - public static class BuilderStrategy - { - private static List> _factories = new List> - { - new Tuple(typeof(AllProperties), new AllProperties()), - new Tuple(typeof(PublicProperties), new PublicProperties()), - new Tuple(typeof(UseConstructor), new UseConstructor()), - new Tuple(typeof(AutoFixture), new AutoFixture()) - }; - - /// - /// Provides access to specified factory. - /// - /// - /// The requested Factory - public static IBuildStrategy Apply() where T : IBuildStrategy - { - return _factories.Where(x => x.Item1 == typeof (T)) - .Select(x => x.Item2) - .First(); - } - } -} \ No newline at end of file diff --git a/TestStack.Dossier/Builder.cs b/TestStack.Dossier/Builder.cs index ca9fd3b..5771216 100644 --- a/TestStack.Dossier/Builder.cs +++ b/TestStack.Dossier/Builder.cs @@ -1,10 +1,16 @@ -using System; - -namespace TestStack.Dossier +namespace TestStack.Dossier { + /// + /// A stand-alone class for building objects on the fly. + /// + /// The type of object this class generates. public class Builder : TestDataBuilder> where T : class { + /// + /// Initialises a new Builder. + /// + /// Returns a new instance of a Builder for the type of T public static Builder CreateNew() { return new Builder(); diff --git a/TestStack.Dossier/BuildStrategies/AllProperties.cs b/TestStack.Dossier/Factories/AllPropertiesFactory.cs similarity index 90% rename from TestStack.Dossier/BuildStrategies/AllProperties.cs rename to TestStack.Dossier/Factories/AllPropertiesFactory.cs index 75c18fb..34bbc6d 100644 --- a/TestStack.Dossier/BuildStrategies/AllProperties.cs +++ b/TestStack.Dossier/Factories/AllPropertiesFactory.cs @@ -1,11 +1,11 @@ using Ploeh.AutoFixture; -namespace TestStack.Dossier.BuildStrategies +namespace TestStack.Dossier.Factories { /// /// Creates an instance of an object by setting all public and private properties. /// - public class AllProperties : IBuildStrategy + public class AllPropertiesFactory : IFactory { /// public TObject BuildObject(TestDataBuilder builder) diff --git a/TestStack.Dossier/BuildStrategies/AutoFixture.cs b/TestStack.Dossier/Factories/AutoFixtureFactory.cs similarity index 83% rename from TestStack.Dossier/BuildStrategies/AutoFixture.cs rename to TestStack.Dossier/Factories/AutoFixtureFactory.cs index 56922a0..831c65b 100644 --- a/TestStack.Dossier/BuildStrategies/AutoFixture.cs +++ b/TestStack.Dossier/Factories/AutoFixtureFactory.cs @@ -1,11 +1,11 @@ using Ploeh.AutoFixture; -namespace TestStack.Dossier.BuildStrategies +namespace TestStack.Dossier.Factories { /// /// Creates an instance of an object with AutoFixture. /// - public class AutoFixture : IBuildStrategy + public class AutoFixtureFactory : IFactory { /// public TObject BuildObject(TestDataBuilder builder) diff --git a/TestStack.Dossier/BuildStrategies/UseConstructor.cs b/TestStack.Dossier/Factories/ConstructorFactory.cs similarity index 66% rename from TestStack.Dossier/BuildStrategies/UseConstructor.cs rename to TestStack.Dossier/Factories/ConstructorFactory.cs index cc1cd5d..13e32a2 100644 --- a/TestStack.Dossier/BuildStrategies/UseConstructor.cs +++ b/TestStack.Dossier/Factories/ConstructorFactory.cs @@ -1,14 +1,15 @@ using System; using System.Linq; using System.Linq.Expressions; +using System.Reflection; using Ploeh.AutoFixture; -namespace TestStack.Dossier.BuildStrategies +namespace TestStack.Dossier.Factories { /// /// Builds the object using the constructor with the most arguments. /// - public class UseConstructor : IBuildStrategy + public class ConstructorFactory : IFactory { /// public TObject BuildObject(TestDataBuilder builder) @@ -24,24 +25,22 @@ public TObject BuildObject(TestDataBuilder var parameterValues = longestConstructor .GetParameters() - .Select(x => CallGetWithType(x.Name, x.ParameterType, typeof(TObject), typeof(TBuilder))); + .Select(x => CallGetWithType(x.Name, x.ParameterType, typeof(TObject), typeof(TBuilder), builder)); return (TObject)longestConstructor.Invoke(parameterValues.ToArray()); } - private object CallGetWithType(string propertyName, Type propertyType, Type objectType, Type builderType) + private static object CallGetWithType(string propertyName, Type propertyType, Type objectType, Type builderType, object builder) { // Make a Func var expressionDelegateType = typeof(Func<,>).MakeGenericType(objectType, propertyType); - - // Make an expression parameter of type TObj var tObjParameterType = Expression.Parameter(objectType); - var valueStoredInBuilder = builderType + var closedGenericGetMethod = builderType .GetMethods() - .First(method => method.Name == "Get" && method.ContainsGenericParameters && method.GetGenericArguments().Length == 1) - .MakeGenericMethod(propertyType) - .Invoke(this, new object[] + .First(IsGenericGetMethod()) + .MakeGenericMethod(propertyType); + var valueStoredInBuilder = closedGenericGetMethod.Invoke(builder, new object[] { Expression.Lambda( expressionDelegateType, @@ -52,5 +51,9 @@ private object CallGetWithType(string propertyName, Type propertyType, Type obje return valueStoredInBuilder; } + private static Func IsGenericGetMethod() + { + return method => method.Name == "Get" && method.ContainsGenericParameters && method.GetGenericArguments().Length == 1; + } } } \ No newline at end of file diff --git a/TestStack.Dossier/BuildStrategies/IBuildStrategy.cs b/TestStack.Dossier/Factories/IFactory.cs similarity index 90% rename from TestStack.Dossier/BuildStrategies/IBuildStrategy.cs rename to TestStack.Dossier/Factories/IFactory.cs index d9b9cac..d320f26 100644 --- a/TestStack.Dossier/BuildStrategies/IBuildStrategy.cs +++ b/TestStack.Dossier/Factories/IFactory.cs @@ -1,9 +1,9 @@ -namespace TestStack.Dossier.BuildStrategies +namespace TestStack.Dossier.Factories { /// /// Interface for object building strategies /// - public interface IBuildStrategy + public interface IFactory { /// /// Takes a builder and generates an object of the specified type. diff --git a/TestStack.Dossier/BuildStrategies/PublicProperties.cs b/TestStack.Dossier/Factories/PublicPropertiesFactory.cs similarity index 90% rename from TestStack.Dossier/BuildStrategies/PublicProperties.cs rename to TestStack.Dossier/Factories/PublicPropertiesFactory.cs index c1ff0fc..b9ba3a1 100644 --- a/TestStack.Dossier/BuildStrategies/PublicProperties.cs +++ b/TestStack.Dossier/Factories/PublicPropertiesFactory.cs @@ -1,11 +1,11 @@ using Ploeh.AutoFixture; -namespace TestStack.Dossier.BuildStrategies +namespace TestStack.Dossier.Factories { /// /// Creates an instance of an object by setting all public properties but not private properties. /// - public class PublicProperties : IBuildStrategy + public class PublicPropertiesFactory : IFactory { /// public TObject BuildObject(TestDataBuilder builder) diff --git a/TestStack.Dossier/IAnonymousValueSupplier.cs b/TestStack.Dossier/IAnonymousValueSupplier.cs index 493debc..9eda5af 100644 --- a/TestStack.Dossier/IAnonymousValueSupplier.cs +++ b/TestStack.Dossier/IAnonymousValueSupplier.cs @@ -28,8 +28,7 @@ public interface IAnonymousValueSupplier /// /// Return an anonymous value for the given property and fixture. /// - /// The type that the property is enclosed in - /// The type of the target property - the required anonymous value is of this type + /// The type that the property is enclosed in /// Anonymous value fixture /// The name of the property to return an anonymous value for /// The anonymous value diff --git a/TestStack.Dossier/TestDataBuilder.cs b/TestStack.Dossier/TestDataBuilder.cs index 0945737..90148cd 100644 --- a/TestStack.Dossier/TestDataBuilder.cs +++ b/TestStack.Dossier/TestDataBuilder.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq.Expressions; -using TestStack.Dossier.BuildStrategies; +using TestStack.Dossier.Factories; using TestStack.Dossier.Lists; namespace TestStack.Dossier @@ -15,6 +15,7 @@ public abstract class TestDataBuilder where TObject : class where TBuilder : TestDataBuilder, new() { + private readonly IFactory _factory; private readonly Dictionary _properties = new Dictionary(StringComparer.InvariantCultureIgnoreCase); private ProxyBuilder _proxyBuilder; @@ -27,7 +28,16 @@ public abstract class TestDataBuilder /// Default Constructor. /// protected TestDataBuilder() + : this(new AllPropertiesFactory()) { + } + + /// + /// Allow object builder factory to be passed in + /// + protected TestDataBuilder(IFactory factory) + { + _factory = factory; Any = new AnonymousValueFixture(); } @@ -76,9 +86,7 @@ public static implicit operator List(TestDataBuilder /// The built object protected virtual TObject BuildObject() { - var model = BuilderStrategy - .Apply() - .BuildObject(this); + var model = _factory.BuildObject(this); return model; } diff --git a/TestStack.Dossier/TestStack.Dossier.csproj b/TestStack.Dossier/TestStack.Dossier.csproj index 2c48472..f00abcf 100644 --- a/TestStack.Dossier/TestStack.Dossier.csproj +++ b/TestStack.Dossier/TestStack.Dossier.csproj @@ -80,11 +80,10 @@ - - - - - + + + + @@ -92,7 +91,7 @@ - + From 37a290d131526c1fa1f61b00d89764585cfc13b3 Mon Sep 17 00:00:00 2001 From: Michael Whelan Date: Sun, 3 May 2015 10:17:45 +0100 Subject: [PATCH 09/10] Updated Builder to allow customisation of factory --- TestStack.Dossier/Builder.cs | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/TestStack.Dossier/Builder.cs b/TestStack.Dossier/Builder.cs index 5771216..b96bb2f 100644 --- a/TestStack.Dossier/Builder.cs +++ b/TestStack.Dossier/Builder.cs @@ -1,4 +1,6 @@ -namespace TestStack.Dossier +using TestStack.Dossier.Factories; + +namespace TestStack.Dossier { /// /// A stand-alone class for building objects on the fly. @@ -7,13 +9,28 @@ public class Builder : TestDataBuilder> where T : class { + /// + public Builder() + : this(new AllPropertiesFactory()) + { + + } + + /// + public Builder(IFactory factory) + : base(factory) { } + /// /// Initialises a new Builder. /// /// Returns a new instance of a Builder for the type of T - public static Builder CreateNew() + public static Builder CreateNew(IFactory factory = null) { - return new Builder(); + if (factory == null) + { + factory = new AllPropertiesFactory(); + } + return new Builder(factory); } } } From 72280f3df6ea4fb7b1abadfac9961f4d3752c99d Mon Sep 17 00:00:00 2001 From: Michael Whelan Date: Sun, 3 May 2015 12:15:23 +0100 Subject: [PATCH 10/10] Added tests for various Factories --- TestStack.Dossier.Tests/BuilderBuildTests.cs | 8 +- .../Factories/FactoryTests.cs | 88 +++++++++++++++++++ .../Stubs/ViewModels/InstructorViewModel.cs | 12 +-- .../TestStack.Dossier.Tests.csproj | 1 + TestStack.Dossier/Builder.cs | 13 +-- .../Factories/ConstructorFactory.cs | 2 +- .../Factories/PublicPropertiesFactory.cs | 17 ++-- TestStack.Dossier/TestDataBuilder.cs | 10 ++- 8 files changed, 120 insertions(+), 31 deletions(-) create mode 100644 TestStack.Dossier.Tests/Factories/FactoryTests.cs diff --git a/TestStack.Dossier.Tests/BuilderBuildTests.cs b/TestStack.Dossier.Tests/BuilderBuildTests.cs index eb9829d..87530a8 100644 --- a/TestStack.Dossier.Tests/BuilderBuildTests.cs +++ b/TestStack.Dossier.Tests/BuilderBuildTests.cs @@ -1,4 +1,5 @@ -using Shouldly; +using System; +using Shouldly; using TestStack.Dossier.Tests.Builders; using TestStack.Dossier.Tests.Stubs.Entities; using TestStack.Dossier.Tests.Stubs.ViewModels; @@ -57,14 +58,15 @@ public void GivenBuilder_WhenCallingSetImplicitly_ShouldOverrideValues() [Fact] public void GivenBuilder_WhenBuildingObjectWithCtorAndPrivateSetters_ShouldSetPrivateSetters() { + var id = Guid.NewGuid(); InstructorViewModel instructor = Builder.CreateNew() .Set(x => x.FirstName, "Pi") .Set(x => x.LastName, "Lanningham") - .Set(x => x.Id, 5); + .Set(x => x.Id, id); instructor.FirstName.ShouldBe("Pi"); instructor.LastName.ShouldBe("Lanningham"); - instructor.Id.ShouldBe(5); + instructor.Id.ShouldBe(id); } } } \ No newline at end of file diff --git a/TestStack.Dossier.Tests/Factories/FactoryTests.cs b/TestStack.Dossier.Tests/Factories/FactoryTests.cs new file mode 100644 index 0000000..c90dc01 --- /dev/null +++ b/TestStack.Dossier.Tests/Factories/FactoryTests.cs @@ -0,0 +1,88 @@ +using System; +using Shouldly; +using TestStack.Dossier.Factories; +using TestStack.Dossier.Tests.Stubs.Entities; +using TestStack.Dossier.Tests.Stubs.ViewModels; +using Xunit; + +namespace TestStack.Dossier.Tests.Factories +{ + public class FactoryTests + { + [Fact] + public void GivenAllPropertiesFactory_WhenBuilding_ThenAllPropertiesSet() + { + InstructorViewModel instructor = Builder.CreateNew(new AllPropertiesFactory()); + + // ctor properties + instructor.Id.ShouldNotBe(Guid.Empty); + instructor.FirstName.ShouldNotBe(null); + instructor.LastName.ShouldNotBe(null); + + // public properties + instructor.Room.ShouldNotBe(null); + instructor.NumberOfStudents.ShouldNotBe(0); + + // private properties + instructor.Subject.ShouldNotBe(null); + instructor.YearsAtSchool.ShouldNotBe(0); + } + + [Fact] + public void GivenAutoFixtureFactory_WhenBuilding_ThenOnlyConstructorAndPublicPropertiesSet() + { + InstructorViewModel instructor = Builder.CreateNew(new AutoFixtureFactory()); + + // ctor properties + instructor.Id.ShouldNotBe(Guid.Empty); + instructor.FirstName.ShouldNotBe(null); + instructor.LastName.ShouldNotBe(null); + + // public properties + instructor.Room.ShouldNotBe(null); + instructor.NumberOfStudents.ShouldNotBe(0); + + // private properties + instructor.Subject.ShouldBe(null); + instructor.YearsAtSchool.ShouldBe(0); + } + + [Fact] + public void GivenConstructorPropertiesFactory_WhenBuilding_ThenOnlyConstructorPropertiesSet() + { + InstructorViewModel instructor = Builder.CreateNew(new ConstructorFactory()); + + // ctor properties + instructor.Id.ShouldNotBe(Guid.Empty); + instructor.FirstName.ShouldNotBe(null); + instructor.LastName.ShouldNotBe(null); + + // public properties + instructor.Room.ShouldBe(null); + instructor.NumberOfStudents.ShouldBe(0); + + // private properties + instructor.Subject.ShouldBe(null); + instructor.YearsAtSchool.ShouldBe(0); + } + + [Fact] + public void GivenPublicPropertiesFactory_WhenBuilding_ThenOnlyConstructorAndPublicPropertiesSet() + { + InstructorViewModel instructor = Builder.CreateNew(new PublicPropertiesFactory()); + + // ctor properties + instructor.Id.ShouldNotBe(Guid.Empty); + instructor.FirstName.ShouldNotBe(null); + instructor.LastName.ShouldNotBe(null); + + // public properties + instructor.Room.ShouldNotBe(null); + instructor.NumberOfStudents.ShouldBeGreaterThan(0); + + // private properties + instructor.Subject.ShouldBe(null); + instructor.YearsAtSchool.ShouldBe(0); + } + } +} diff --git a/TestStack.Dossier.Tests/Stubs/ViewModels/InstructorViewModel.cs b/TestStack.Dossier.Tests/Stubs/ViewModels/InstructorViewModel.cs index 44866e0..b0db3e9 100644 --- a/TestStack.Dossier.Tests/Stubs/ViewModels/InstructorViewModel.cs +++ b/TestStack.Dossier.Tests/Stubs/ViewModels/InstructorViewModel.cs @@ -4,16 +4,16 @@ namespace TestStack.Dossier.Tests.Stubs.ViewModels { public class InstructorViewModel { - public InstructorViewModel(int id, string firstName, string lastName) + public InstructorViewModel(Guid id, string firstName, string lastName) { Id = id; FirstName = firstName; LastName = lastName; } - public int Id { get; private set; } + public Guid Id { get; private set; } - public string LastName { get; private set; } + public string LastName { get; set; } public string FirstName { get; private set; } public string FullName @@ -23,8 +23,10 @@ public string FullName return FirstName + " " + LastName; } } - public DateTime JoinDate { get; set; } + public string Room{ get; set; } - public Grade Grade { get; set; } + public string Subject{ get; private set; } + public int YearsAtSchool { get; private set; } + public int NumberOfStudents { get; set; } } } diff --git a/TestStack.Dossier.Tests/TestStack.Dossier.Tests.csproj b/TestStack.Dossier.Tests/TestStack.Dossier.Tests.csproj index c79c0ad..0348725 100644 --- a/TestStack.Dossier.Tests/TestStack.Dossier.Tests.csproj +++ b/TestStack.Dossier.Tests/TestStack.Dossier.Tests.csproj @@ -60,6 +60,7 @@ + diff --git a/TestStack.Dossier/Builder.cs b/TestStack.Dossier/Builder.cs index b96bb2f..08d9f49 100644 --- a/TestStack.Dossier/Builder.cs +++ b/TestStack.Dossier/Builder.cs @@ -9,17 +9,6 @@ namespace TestStack.Dossier public class Builder : TestDataBuilder> where T : class { - /// - public Builder() - : this(new AllPropertiesFactory()) - { - - } - - /// - public Builder(IFactory factory) - : base(factory) { } - /// /// Initialises a new Builder. /// @@ -30,7 +19,7 @@ public static Builder CreateNew(IFactory factory = null) { factory = new AllPropertiesFactory(); } - return new Builder(factory); + return new Builder {Factory = factory}; } } } diff --git a/TestStack.Dossier/Factories/ConstructorFactory.cs b/TestStack.Dossier/Factories/ConstructorFactory.cs index 13e32a2..391aa2c 100644 --- a/TestStack.Dossier/Factories/ConstructorFactory.cs +++ b/TestStack.Dossier/Factories/ConstructorFactory.cs @@ -12,7 +12,7 @@ namespace TestStack.Dossier.Factories public class ConstructorFactory : IFactory { /// - public TObject BuildObject(TestDataBuilder builder) + public virtual TObject BuildObject(TestDataBuilder builder) where TObject : class where TBuilder : TestDataBuilder, new() { diff --git a/TestStack.Dossier/Factories/PublicPropertiesFactory.cs b/TestStack.Dossier/Factories/PublicPropertiesFactory.cs index b9ba3a1..4af57f3 100644 --- a/TestStack.Dossier/Factories/PublicPropertiesFactory.cs +++ b/TestStack.Dossier/Factories/PublicPropertiesFactory.cs @@ -1,23 +1,21 @@ -using Ploeh.AutoFixture; +using System.Reflection; namespace TestStack.Dossier.Factories { /// /// Creates an instance of an object by setting all public properties but not private properties. /// - public class PublicPropertiesFactory : IFactory + public class PublicPropertiesFactory : ConstructorFactory { /// - public TObject BuildObject(TestDataBuilder builder) - where TObject : class - where TBuilder : TestDataBuilder, new() + public override TObject BuildObject(TestDataBuilder builder) { - var model = builder.Any.Fixture.Create(); + var model = base.BuildObject(builder); var properties = Reflector.GetSettablePropertiesFor(); foreach (var property in properties) { - if (property.CanWrite && property.GetSetMethod().IsPublic) + if (PropertySetterIsPublic(property)) { var val = builder.Get(property.PropertyType, property.Name); property.SetValue(model, val, null); @@ -26,5 +24,10 @@ public TObject BuildObject(TestDataBuilder return model; } + + private static bool PropertySetterIsPublic(PropertyInfo property) + { + return property.CanWrite && property.GetSetMethod() != null; + } } } \ No newline at end of file diff --git a/TestStack.Dossier/TestDataBuilder.cs b/TestStack.Dossier/TestDataBuilder.cs index 90148cd..c918f5a 100644 --- a/TestStack.Dossier/TestDataBuilder.cs +++ b/TestStack.Dossier/TestDataBuilder.cs @@ -15,10 +15,14 @@ public abstract class TestDataBuilder where TObject : class where TBuilder : TestDataBuilder, new() { - private readonly IFactory _factory; private readonly Dictionary _properties = new Dictionary(StringComparer.InvariantCultureIgnoreCase); private ProxyBuilder _proxyBuilder; + /// + /// The factory used to create the instance of TObject. + /// + public IFactory Factory; + /// /// The list builder instance (if this ia a list builder proxy). /// @@ -37,7 +41,7 @@ protected TestDataBuilder() /// protected TestDataBuilder(IFactory factory) { - _factory = factory; + Factory = factory; Any = new AnonymousValueFixture(); } @@ -86,7 +90,7 @@ public static implicit operator List(TestDataBuilder /// The built object protected virtual TObject BuildObject() { - var model = _factory.BuildObject(this); + var model = Factory.BuildObject(this); return model; }