Skip to content

Commit 205c61e

Browse files
committed
Added a static Builder<T> class to emulate NBuilder behaviour
1 parent 7ce4bb3 commit 205c61e

17 files changed

Lines changed: 483 additions & 16 deletions
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using Shouldly;
4+
using TestStack.Dossier.DataSources.Generators;
5+
using TestStack.Dossier.Lists;
6+
using TestStack.Dossier.Tests.Builders;
7+
using TestStack.Dossier.Tests.Entities;
8+
using Xunit;
9+
10+
namespace TestStack.Dossier.Tests
11+
{
12+
public class BuilderBuildListTests
13+
{
14+
[Fact]
15+
public void GivenANormalBuilderInstance_WhenCallingIsListBuilderProxy_ThenReturnFalse()
16+
{
17+
var builder = Builder<Customer>.CreateNew();
18+
19+
builder.IsListBuilderProxy().ShouldBe(false);
20+
}
21+
22+
[Fact]
23+
public void GivenAListBuilderProxyInstance_WhenCallingIsListBuilderProxy_ThenReturnTrue()
24+
{
25+
var builder = Builder<Customer>.CreateListOfSize(1).TheFirst(1);
26+
27+
builder.IsListBuilderProxy().ShouldBe(true);
28+
}
29+
30+
[Fact]
31+
public void GivenListOfBuilders_WhenCallingBuildListExplicitly_ThenAListOfEntitiesOfTheRightSizeShouldBeReturned()
32+
{
33+
var builders = Builder<Customer>.CreateListOfSize(5);
34+
35+
var entities = builders.BuildList();
36+
37+
entities.Count.ShouldBe(5);
38+
}
39+
40+
[Fact]
41+
public void GivenListOfBuilders_WhenCallingBuildListImplicitly_ThenAListOfEntitiesOfTheRightSizeShouldBeReturned()
42+
{
43+
List<Customer> entities = Builder<Customer>.CreateListOfSize(5);
44+
45+
entities.Count.ShouldBe(5);
46+
}
47+
48+
[Fact]
49+
public void GivenListOfBuilders_WhenCallingBuildListExplicitly_ThenAListOfEntitiesOfTheRightTypeShouldBeReturned()
50+
{
51+
var builders = Builder<Customer>.CreateListOfSize(5);
52+
53+
var entities = builders.BuildList();
54+
55+
entities.ShouldBeAssignableTo<IList<Customer>>();
56+
}
57+
58+
[Fact]
59+
public void GivenListOfBuilders_WhenCallingBuildListImplicitly_ThenAListOfEntitiesOfTheRightTypeShouldBeReturned()
60+
{
61+
List<Customer> entities = Builder<Customer>.CreateListOfSize(5);
62+
63+
entities.ShouldBeAssignableTo<IList<Customer>>();
64+
}
65+
66+
[Fact]
67+
public void GivenListOfBuilders_WhenCallingBuildListExplicitly_ThenAListOfUniqueEntitiesShouldBeReturned()
68+
{
69+
var builders = Builder<Customer>.CreateListOfSize(5);
70+
71+
var entities = builders.BuildList();
72+
73+
entities[0].ShouldNotBe(entities[1]);
74+
entities[0].ShouldNotBe(entities[2]);
75+
entities[0].ShouldNotBe(entities[3]);
76+
entities[0].ShouldNotBe(entities[4]);
77+
entities[1].ShouldNotBe(entities[2]);
78+
entities[1].ShouldNotBe(entities[3]);
79+
entities[1].ShouldNotBe(entities[4]);
80+
entities[2].ShouldNotBe(entities[3]);
81+
entities[2].ShouldNotBe(entities[4]);
82+
entities[3].ShouldNotBe(entities[4]);
83+
}
84+
85+
[Fact]
86+
public void GivenListOfBuilders_WhenCallingBuildListImplicitly_ThenAListOfUniqueEntitiesShouldBeReturned()
87+
{
88+
List<Customer> entities = Builder<Customer>.CreateListOfSize(5);
89+
90+
entities[0].ShouldNotBe(entities[1]);
91+
entities[0].ShouldNotBe(entities[2]);
92+
entities[0].ShouldNotBe(entities[3]);
93+
entities[0].ShouldNotBe(entities[4]);
94+
entities[1].ShouldNotBe(entities[2]);
95+
entities[1].ShouldNotBe(entities[3]);
96+
entities[1].ShouldNotBe(entities[4]);
97+
entities[2].ShouldNotBe(entities[3]);
98+
entities[2].ShouldNotBe(entities[4]);
99+
entities[3].ShouldNotBe(entities[4]);
100+
}
101+
102+
[Fact]
103+
public void GivenListOfBuildersWithCustomisation_WhenBuildingEntitiesExplicitly_ThenTheCustomisationShouldTakeEffect()
104+
{
105+
var generator = new SequentialGenerator(0, 100);
106+
var list = CustomerBuilder.CreateListOfSize(3)
107+
.All().With(b => b.WithFirstName(generator.Generate().ToString()));
108+
109+
var data = list.BuildList();
110+
111+
data.Select(c => c.FirstName).ToArray()
112+
.ShouldBe(new[] { "0", "1", "2" });
113+
}
114+
115+
[Fact]
116+
public void GivenListOfBuildersWithCustomisation_WhenBuildingEntitiesImplicitly_ThenTheCustomisationShouldTakeEffect()
117+
{
118+
var generator = new SequentialGenerator(0, 100);
119+
120+
List<Customer> data = CustomerBuilder.CreateListOfSize(3)
121+
.All().With(b => b.WithFirstName(generator.Generate().ToString()));
122+
123+
data.Select(c => c.FirstName).ToArray()
124+
.ShouldBe(new[] { "0", "1", "2" });
125+
}
126+
127+
[Fact]
128+
public void GivenListOfBuildersWithARangeOfCustomisationMethods_WhenBuildingEntitiesExplicitly_ThenThenTheListIsBuiltAndModifiedCorrectly()
129+
{
130+
var i = 0;
131+
var customers = CustomerBuilder.CreateListOfSize(5)
132+
.TheFirst(1).WithFirstName("First")
133+
.TheNext(1).WithLastName("Next Last")
134+
.TheLast(1).WithLastName("Last Last")
135+
.ThePrevious(2).With(b => b.WithLastName("last" + (++i).ToString()))
136+
.All().WhoJoinedIn(1999)
137+
.BuildList();
138+
139+
customers.ShouldBeAssignableTo<IList<Customer>>();
140+
customers.Count.ShouldBe(5);
141+
customers[0].FirstName.ShouldBe("First");
142+
customers[1].LastName.ShouldBe("Next Last");
143+
customers[2].LastName.ShouldBe("last1");
144+
customers[3].LastName.ShouldBe("last2");
145+
customers[4].LastName.ShouldBe("Last Last");
146+
customers.ShouldAllBe(c => c.YearJoined == 1999);
147+
}
148+
149+
[Fact]
150+
public void GivenListOfBuildersWithARangeOfCustomisationMethods_WhenBuildingEntitiesImplicitly_ThenThenTheListIsBuiltAndModifiedCorrectly()
151+
{
152+
var i = 0;
153+
List<Customer> customers = CustomerBuilder.CreateListOfSize(5)
154+
.TheFirst(1).WithFirstName("First")
155+
.TheNext(1).WithLastName("Next Last")
156+
.TheLast(1).WithLastName("Last Last")
157+
.ThePrevious(2).With(b => b.WithLastName("last" + (++i).ToString()))
158+
.All().WhoJoinedIn(1999);
159+
160+
customers.ShouldBeAssignableTo<IList<Customer>>();
161+
customers.Count.ShouldBe(5);
162+
customers[0].FirstName.ShouldBe("First");
163+
customers[1].LastName.ShouldBe("Next Last");
164+
customers[2].LastName.ShouldBe("last1");
165+
customers[3].LastName.ShouldBe("last2");
166+
customers[4].LastName.ShouldBe("Last Last");
167+
customers.ShouldAllBe(c => c.YearJoined == 1999);
168+
}
169+
170+
[Fact]
171+
public void WhenBuildingEntitiesExplicitly_ThenTheAnonymousValueFixtureIsSharedAcrossBuilders()
172+
{
173+
var customers = CustomerBuilder.CreateListOfSize(5).BuildList();
174+
175+
customers[0].CustomerClass.ShouldBe(CustomerClass.Normal);
176+
customers[1].CustomerClass.ShouldBe(CustomerClass.Bronze);
177+
customers[2].CustomerClass.ShouldBe(CustomerClass.Silver);
178+
customers[3].CustomerClass.ShouldBe(CustomerClass.Gold);
179+
customers[4].CustomerClass.ShouldBe(CustomerClass.Platinum);
180+
}
181+
182+
[Fact]
183+
public void WhenBuildingEntitiesImplicitly_ThenTheAnonymousValueFixtureIsSharedAcrossBuilders()
184+
{
185+
List<Customer> customers = CustomerBuilder.CreateListOfSize(5);
186+
187+
customers[0].CustomerClass.ShouldBe(CustomerClass.Normal);
188+
customers[1].CustomerClass.ShouldBe(CustomerClass.Bronze);
189+
customers[2].CustomerClass.ShouldBe(CustomerClass.Silver);
190+
customers[3].CustomerClass.ShouldBe(CustomerClass.Gold);
191+
customers[4].CustomerClass.ShouldBe(CustomerClass.Platinum);
192+
}
193+
}
194+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
using Shouldly;
2+
using TestStack.Dossier.Tests.Builders;
3+
using TestStack.Dossier.Tests.Entities;
4+
using Xunit;
5+
6+
namespace TestStack.Dossier.Tests
7+
{
8+
public class BuilderBuildTests
9+
{
10+
[Fact]
11+
public void GivenBasicBuilder_WhenCallingBuildExplicitly_ThenReturnAnObject()
12+
{
13+
var builder = Builder<Customer>.CreateNew();
14+
15+
var customer = builder.Build();
16+
17+
customer.ShouldBeOfType<Customer>();
18+
}
19+
20+
[Fact]
21+
public void GivenBuilder_WhenCallingSetExplicitly_ShouldOverrideValues()
22+
{
23+
var builder = Builder<Customer>.CreateNew()
24+
.Set(x => x.FirstName, "Pi")
25+
.Set(x => x.LastName, "Lanningham")
26+
.Set(x => x.YearJoined, 2014);
27+
28+
var customer = builder.Build();
29+
30+
customer.FirstName.ShouldBe("Pi");
31+
customer.LastName.ShouldBe("Lanningham");
32+
customer.YearJoined.ShouldBe(2014);
33+
}
34+
35+
[Fact]
36+
public void GivenBasicBuilder_WhenCallingBuildImplicitly_ThenReturnAnObject()
37+
{
38+
Customer customer = Builder<Customer>.CreateNew();
39+
40+
customer.ShouldBeOfType<Customer>();
41+
}
42+
43+
[Fact]
44+
public void GivenBuilder_WhenCallingSetImplicitly_ShouldOverrideValues()
45+
{
46+
Customer customer = Builder<Customer>.CreateNew()
47+
.Set(x => x.FirstName, "Pi")
48+
.Set(x => x.LastName, "Lanningham")
49+
.Set(x => x.YearJoined, 2014);
50+
51+
customer.FirstName.ShouldBe("Pi");
52+
customer.LastName.ShouldBe("Lanningham");
53+
customer.YearJoined.ShouldBe(2014);
54+
}
55+
}
56+
}

TestStack.Dossier.Tests/GetAnonymousTests.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Shouldly;
1+
using System;
2+
using Shouldly;
23
using TestStack.Dossier.DataSources.Person;
34
using TestStack.Dossier.Lists;
45
using TestStack.Dossier.Tests.Builders;
@@ -113,9 +114,20 @@ public bool CanSupplyValue<TObject, TValue>(string propertyName)
113114
&& propertyName.ToLower().StartsWith("year");
114115
}
115116

117+
public bool CanSupplyValue(Type type, string propertyName)
118+
{
119+
return type == typeof(int)
120+
&& propertyName.ToLower().StartsWith("year");
121+
}
122+
116123
public TValue GenerateAnonymousValue<TObject, TValue>(AnonymousValueFixture any, string propertyName)
117124
{
118125
return (TValue)(object)_year++;
119126
}
127+
128+
public object GenerateAnonymousValue(AnonymousValueFixture any, Type type, string propertyName)
129+
{
130+
return _year++;
131+
}
120132
}
121133
}

TestStack.Dossier.Tests/TestHelpers/StaticAnonymousValueSupplier.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
namespace TestStack.Dossier.Tests.TestHelpers
1+
using System;
2+
3+
namespace TestStack.Dossier.Tests.TestHelpers
24
{
35
public class StaticAnonymousValueSupplier : IAnonymousValueSupplier
46
{
@@ -14,9 +16,19 @@ public bool CanSupplyValue<TObject, TValue>(string propertyName)
1416
return typeof(TValue) == _valueToSupply.GetType();
1517
}
1618

19+
public bool CanSupplyValue(Type type, string propertyName)
20+
{
21+
return type == _valueToSupply.GetType();
22+
}
23+
1724
public TValue GenerateAnonymousValue<TObject, TValue>(AnonymousValueFixture any, string propertyName)
1825
{
1926
return (TValue) _valueToSupply;
2027
}
28+
29+
public object GenerateAnonymousValue(AnonymousValueFixture any, Type type, string propertyName)
30+
{
31+
return _valueToSupply;
32+
}
2133
}
2234
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@
5454
</Reference>
5555
</ItemGroup>
5656
<ItemGroup>
57+
<Compile Include="BuilderBuildListTests.cs" />
58+
<Compile Include="BuilderBuildTests.cs" />
5759
<Compile Include="ChildBuilderTests.cs" />
5860
<Compile Include="Entities\CustomerClass.cs" />
5961
<Compile Include="DataSources\DataSourceTests.cs" />

TestStack.Dossier/AnonymousValueFixture.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,5 +90,15 @@ public T Get<TObject, T>(Expression<Func<TObject, T>> property)
9090

9191
return valueSupplier.GenerateAnonymousValue<TObject, T>(this, propertyName);
9292
}
93+
94+
public object Get(Type type, string propertyName)
95+
{
96+
var valueSupplier = LocalValueSuppliers
97+
.Concat(GlobalValueSuppliers)
98+
.Concat(DefaultValueSuppliers)
99+
.First(s => s.CanSupplyValue(type,propertyName));
100+
101+
return valueSupplier.GenerateAnonymousValue(this, type, propertyName);
102+
}
93103
}
94104
}

TestStack.Dossier/Builder.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System;
2+
3+
namespace TestStack.Dossier
4+
{
5+
public class Builder<T> : TestDataBuilder<T, Builder<T>>
6+
where T : class
7+
{
8+
public static Builder<T> CreateNew()
9+
{
10+
return new Builder<T>();
11+
}
12+
}
13+
}

TestStack.Dossier/IAnonymousValueSupplier.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
namespace TestStack.Dossier
1+
using System;
2+
3+
namespace TestStack.Dossier
24
{
35
/// <summary>
46
/// Inheritors can supply an anonymous value.
@@ -14,6 +16,14 @@ public interface IAnonymousValueSupplier
1416
/// <returns>Whether or not this supplier can supply an anonymous value</returns>
1517
bool CanSupplyValue<TObject, TValue>(string propertyName);
1618

19+
/// <summary>
20+
/// Returns whether or not this supplier can supply an anonymous value for the given property.
21+
/// </summary>
22+
/// <param name="type">The type of the property to generate a value for</param>
23+
/// <param name="propertyName">The name of the property to generate a value for</param>
24+
/// <returns>Whether or not this supplier can supply an anonymous value</returns>
25+
bool CanSupplyValue(Type type, string propertyName);
26+
1727
/// <summary>
1828
/// Return an anonymous value for the given property and fixture.
1929
/// </summary>
@@ -23,5 +33,15 @@ public interface IAnonymousValueSupplier
2333
/// <param name="propertyName">The name of the property to return an anonymous value for</param>
2434
/// <returns>The anonymous value</returns>
2535
TValue GenerateAnonymousValue<TObject, TValue>(AnonymousValueFixture any, string propertyName);
36+
37+
/// <summary>
38+
/// Return an anonymous value for the given property and fixture.
39+
/// </summary>
40+
/// <typeparam name="TObject">The type that the property is enclosed in</typeparam>
41+
/// <typeparam name="TValue">The type of the target property - the required anonymous value is of this type</typeparam>
42+
/// <param name="any">Anonymous value fixture</param>
43+
/// <param name="propertyName">The name of the property to return an anonymous value for</param>
44+
/// <returns>The anonymous value</returns>
45+
object GenerateAnonymousValue(AnonymousValueFixture any, Type type, string propertyName);
2646
}
2747
}

0 commit comments

Comments
 (0)