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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions TestStack.Dossier.Tests/BuildTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,19 @@ public void GivenBuilder_WhenCallingSetImplicitly_ShouldOverrideValues()
customer.LastName.ShouldBe("Lanningham");
customer.YearJoined.ShouldBe(2014);
}

[Fact]
public void GivenBuilderUsingConstructorReflection_WhenCallingBuildExplicitly_ShouldOverrideValues()
{
Customer customer = new AutoConstructorCustomerBuilder()
.WithFirstName("Bruce")
.WithLastName("Wayne")
.WhoJoinedIn(2012)
.Build();

customer.FirstName.ShouldBe("Bruce");
customer.LastName.ShouldBe("Wayne");
customer.YearJoined.ShouldBe(2012);
}
}
}
32 changes: 32 additions & 0 deletions TestStack.Dossier.Tests/Builders/AutoConstructorCustomerBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TestStack.Dossier.Tests.Entities;

namespace TestStack.Dossier.Tests.Builders
{
class AutoConstructorCustomerBuilder : TestDataBuilder<Customer, AutoConstructorCustomerBuilder>
{
protected override Customer BuildObject()
{
return BuildByConstructor();
}

public AutoConstructorCustomerBuilder WithFirstName(string firstName)
{
return Set(x => x.FirstName, firstName);
}

public AutoConstructorCustomerBuilder WithLastName(string lastName)
{
return Set(x => x.LastName, lastName);
}

public AutoConstructorCustomerBuilder WhoJoinedIn(int year)
{
return Set(x => x.YearJoined, year);
}
}
}
6 changes: 5 additions & 1 deletion TestStack.Dossier.Tests/TestStack.Dossier.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<TargetFrameworkProfile />
<NuGetPackageImportStamp>d4853673</NuGetPackageImportStamp>
<NuGetPackageImportStamp>660882d1</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
Expand Down Expand Up @@ -54,6 +54,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Builders\AutoConstructorCustomerBuilder.cs" />
<Compile Include="ChildBuilderTests.cs" />
<Compile Include="Entities\CustomerClass.cs" />
<Compile Include="DataSources\DataSourceTests.cs" />
Expand Down Expand Up @@ -100,6 +101,9 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
Expand Down
47 changes: 45 additions & 2 deletions TestStack.Dossier/TestDataBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Ploeh.AutoFixture;
using TestStack.Dossier.Lists;

namespace TestStack.Dossier
Expand All @@ -15,7 +16,7 @@ public abstract class TestDataBuilder<TObject, TBuilder>
where TObject : class
where TBuilder : TestDataBuilder<TObject, TBuilder>, new()
{
private readonly Dictionary<string, object> _properties = new Dictionary<string, object>();
private readonly Dictionary<string, object> _properties = new Dictionary<string, object>(StringComparer.InvariantCultureIgnoreCase);
private ProxyBuilder<TObject> _proxyBuilder;

/// <summary>
Expand Down Expand Up @@ -117,7 +118,7 @@ public TValue Get<TValue>(Expression<Func<TObject, TValue>> property)
if (!Has(property))
return Any.Get(property);

return (TValue)_properties[PropertyNameGetter.Get(property)];
return (TValue) _properties[PropertyNameGetter.Get(property)];
}

/// <summary>
Expand Down Expand Up @@ -182,5 +183,47 @@ protected virtual TChildBuilder GetChildBuilder<TChildObject, TChildBuilder>(Fun
modifier(childBuilder);
return childBuilder;
}

/// <summary>
/// Builds the object using the constructor with the most arguments.
/// </summary>
/// <returns></returns>
protected 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<TObj, TPropertyType>
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)
.GetMethod("Get")
.MakeGenericMethod(propertyType)
.Invoke(this, new object[]
{
Expression.Lambda(
expressionDelegateType,
Expression.Property(tObjParameterType, propertyName),
tObjParameterType)
});

return valueStoredInBuilder;
}
}
}