Skip to content

Commit 6551bff

Browse files
committed
Fixed merge conflicts from PR#32
2 parents 7632277 + 4607939 commit 6551bff

4 files changed

Lines changed: 91 additions & 2 deletions

File tree

TestStack.Dossier.Tests/BuildTests.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,5 +80,19 @@ public void GivenBuilder_WhenCallingSetImplicitly_ShouldOverrideValues()
8080
customer.LastName.ShouldBe("Lanningham");
8181
customer.YearJoined.ShouldBe(2014);
8282
}
83+
84+
[Fact]
85+
public void GivenBuilderUsingConstructorReflection_WhenCallingBuildExplicitly_ShouldOverrideValues()
86+
{
87+
Customer customer = new AutoConstructorCustomerBuilder()
88+
.WithFirstName("Bruce")
89+
.WithLastName("Wayne")
90+
.WhoJoinedIn(2012)
91+
.Build();
92+
93+
customer.FirstName.ShouldBe("Bruce");
94+
customer.LastName.ShouldBe("Wayne");
95+
customer.YearJoined.ShouldBe(2012);
96+
}
8397
}
8498
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using TestStack.Dossier.Tests.Stubs.Entities;
2+
3+
namespace TestStack.Dossier.Tests.Builders
4+
{
5+
class AutoConstructorCustomerBuilder : TestDataBuilder<Customer, AutoConstructorCustomerBuilder>
6+
{
7+
protected override Customer BuildObject()
8+
{
9+
return BuildByConstructor();
10+
}
11+
12+
public AutoConstructorCustomerBuilder WithFirstName(string firstName)
13+
{
14+
return Set(x => x.FirstName, firstName);
15+
}
16+
17+
public AutoConstructorCustomerBuilder WithLastName(string lastName)
18+
{
19+
return Set(x => x.LastName, lastName);
20+
}
21+
22+
public AutoConstructorCustomerBuilder WhoJoinedIn(int year)
23+
{
24+
return Set(x => x.YearJoined, year);
25+
}
26+
}
27+
}

TestStack.Dossier.Tests/TestStack.Dossier.Tests.csproj

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<FileAlignment>512</FileAlignment>
1414
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
1515
<TargetFrameworkProfile />
16-
<NuGetPackageImportStamp>d4853673</NuGetPackageImportStamp>
16+
<NuGetPackageImportStamp>660882d1</NuGetPackageImportStamp>
1717
</PropertyGroup>
1818
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
1919
<DebugSymbols>true</DebugSymbols>
@@ -58,6 +58,7 @@
5858
<Compile Include="BuilderBuildListTests.cs" />
5959
<Compile Include="BuilderBuildTests.cs" />
6060
<Compile Include="Builders\StudentViewModelBuilder.cs" />
61+
<Compile Include="Builders\AutoConstructorCustomerBuilder.cs" />
6162
<Compile Include="ChildBuilderTests.cs" />
6263
<Compile Include="Stubs\Entities\Company.cs" />
6364
<Compile Include="Stubs\Entities\Customer.cs" />
@@ -107,6 +108,9 @@
107108
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
108109
</Content>
109110
</ItemGroup>
111+
<ItemGroup>
112+
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
113+
</ItemGroup>
110114
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
111115
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
112116
Other similar extension points exist, see Microsoft.Common.targets.

TestStack.Dossier/TestDataBuilder.cs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Linq;
34
using System.Linq.Expressions;
45
using System.Reflection;
56
using Ploeh.AutoFixture;
@@ -16,7 +17,7 @@ public abstract class TestDataBuilder<TObject, TBuilder>
1617
where TObject : class
1718
where TBuilder : TestDataBuilder<TObject, TBuilder>, new()
1819
{
19-
private readonly Dictionary<string, object> _properties = new Dictionary<string, object>();
20+
private readonly Dictionary<string, object> _properties = new Dictionary<string, object>(StringComparer.InvariantCultureIgnoreCase);
2021
private ProxyBuilder<TObject> _proxyBuilder;
2122

2223
/// <summary>
@@ -215,5 +216,48 @@ protected virtual TChildBuilder GetChildBuilder<TChildObject, TChildBuilder>(Fun
215216
modifier(childBuilder);
216217
return childBuilder;
217218
}
219+
220+
/// <summary>
221+
/// Builds the object using the constructor with the most arguments.
222+
/// </summary>
223+
/// <returns></returns>
224+
protected virtual TObject BuildByConstructor()
225+
{
226+
var longestConstructor = typeof (TObject)
227+
.GetConstructors()
228+
.OrderByDescending(x => x.GetParameters().Length)
229+
.FirstOrDefault();
230+
231+
if (longestConstructor == null) throw new ObjectCreationException();
232+
233+
var parameterValues = longestConstructor
234+
.GetParameters()
235+
.Select(x => CallGetWithType(x.Name, x.ParameterType));
236+
237+
return (TObject) longestConstructor.Invoke(parameterValues.ToArray());
238+
}
239+
240+
private object CallGetWithType(string propertyName, Type propertyType)
241+
{
242+
// Make a Func<TObj, TPropertyType>
243+
var expressionDelegateType = typeof(Func<,>).MakeGenericType(typeof(TObject), propertyType);
244+
245+
// Make an expression parameter of type TObj
246+
var tObjParameterType = Expression.Parameter(typeof(TObject));
247+
248+
var valueStoredInBuilder = typeof(TBuilder)
249+
.GetMethods()
250+
.First(method => method.Name == "Get" && method.ContainsGenericParameters && method.GetGenericArguments().Length ==1)
251+
.MakeGenericMethod(propertyType)
252+
.Invoke(this, new object[]
253+
{
254+
Expression.Lambda(
255+
expressionDelegateType,
256+
Expression.Property(tObjParameterType, propertyName),
257+
tObjParameterType)
258+
});
259+
260+
return valueStoredInBuilder;
261+
}
218262
}
219263
}

0 commit comments

Comments
 (0)