Skip to content

Commit 67df72a

Browse files
committed
Merge pull request #36 from Quantumplation/SetLambda
Adds a Set overload which takes a lambda factory method
2 parents 1c8fe7b + 1d1d47d commit 67df72a

File tree

5 files changed

+81
-28
lines changed

5 files changed

+81
-28
lines changed

CONTRIBUTOR_GUIDELINES.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Contributor Guidelines
2+
======================
3+
4+
Hi! Thank you for your interest in contributing to this open source library!
5+
We ask that you follow the following style guidelines when submitting pull
6+
requests, to keep the code consistent and maintainable.
7+
8+
- Do not put an if clause and it's statement on the same line: separate them
9+
with a new-line and indent accordingly.
10+
11+
(This file will be expanded as more guidelines are established by the maintainer)

TestStack.Dossier.Tests/BuildTests.cs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Shouldly;
1+
using System.Collections.Generic;
2+
using Shouldly;
23
using TestStack.Dossier.Tests.TestHelpers.Builders;
34
using TestStack.Dossier.Tests.TestHelpers.Objects.Entities;
45
using Xunit;
@@ -47,6 +48,32 @@ public void GivenBuilder_WhenCallingSetExplicitly_ShouldOverrideValues()
4748
customer.YearJoined.ShouldBe(2014);
4849
}
4950

51+
[Fact]
52+
public void GivenBuilder_WhenCallingSetWithLambda_ShouldInvokeEachTime()
53+
{
54+
int counter = 2014;
55+
var builder = new CustomerBuilder()
56+
.Set(x => x.FirstName, "Pi")
57+
.Set(x => x.LastName, "Lanningham")
58+
.Set(x => x.YearJoined, () => counter++);
59+
60+
var customerA = builder.Build();
61+
var customerB = builder.Build();
62+
63+
customerA.YearJoined.ShouldBe(2014);
64+
customerB.YearJoined.ShouldBe(2015);
65+
66+
List<Customer> customerList = CustomerBuilder.CreateListOfSize(10)
67+
.All()
68+
.Set(x => x.YearJoined, () => counter++);
69+
int newCounter = 2016;
70+
foreach (var c in customerList)
71+
{
72+
c.YearJoined.ShouldBe(newCounter++);
73+
}
74+
75+
}
76+
5077
[Fact]
5178
public void GivenBasicBuilder_WhenCallingBuildImplicitly_ThenReturnAnObject()
5279
{

TestStack.Dossier.Tests/ProxyBuilderTests.cs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class ProxyBuilderTests
1212
[Fact]
1313
public void GivenClassToProxyWithNoProperties_WhenBuildingProxy_ReturnAClassWithNoReturnsValuesSet()
1414
{
15-
var proxyBuilder = new ProxyBuilder<Customer>(new Dictionary<string, object>());
15+
var proxyBuilder = new ProxyBuilder<Customer>(new Dictionary<string, Func<object>>());
1616

1717
var proxy = proxyBuilder.Build();
1818

@@ -24,33 +24,34 @@ public void GivenClassToProxyWithNoProperties_WhenBuildingProxy_ReturnAClassWith
2424
[Fact]
2525
public void GivenClassToProxyWithNoProperties_WhenBuildingProxy_ReturnAnNSubstituteProxyOfThatClass()
2626
{
27-
var proxyBuilder = new ProxyBuilder<Customer>(new Dictionary<string, object>());
27+
var proxyBuilder = new ProxyBuilder<Customer>(new Dictionary<string, Func<object>>());
2828

2929
var proxy = proxyBuilder.Build();
3030

3131
proxy.DidNotReceive().CustomerForHowManyYears(Arg.Any<DateTime>());
3232
}
3333

3434
[Fact]
35-
public void GivenClassToProxyWithSinglePropertyValue_WhenBuildingProxy_ReturnAClassWithReturnValueSet()
35+
public void GivenClassToProxyWithSinglePropertyValue_WhenBuildingProxy_ReturnAClassWithReturnValueSetFromFunction()
3636
{
37-
var proxyBuilder = new ProxyBuilder<Customer>(new Dictionary<string, object> {{"FirstName", "FirstName"}});
37+
int nonce = new Random().Next(0, 100);
38+
var proxyBuilder = new ProxyBuilder<Customer>(new Dictionary<string, Func<object>> {{"FirstName", () => "FirstName" + nonce}});
3839

3940
var proxy = proxyBuilder.Build();
4041

41-
proxy.FirstName.ShouldBe("FirstName");
42+
proxy.FirstName.ShouldBe("FirstName" + nonce);
4243
proxy.LastName.ShouldBe(string.Empty);
4344
proxy.YearJoined.ShouldBe(0);
4445
}
4546

4647
[Fact]
4748
public void GivenClassToProxyWithMultiplePropertyValues_WhenBuildingProxy_ReturnAClassWithReturnValueSet()
4849
{
49-
var proxyBuilder = new ProxyBuilder<Customer>(new Dictionary<string, object>
50+
var proxyBuilder = new ProxyBuilder<Customer>(new Dictionary<string, Func<object>>
5051
{
51-
{ "FirstName", "FirstName" },
52-
{ "LastName", "LastName" },
53-
{ "YearJoined", 1 },
52+
{ "FirstName", () => "FirstName" },
53+
{ "LastName", () => "LastName" },
54+
{ "YearJoined", () => 1 },
5455
}
5556
);
5657

@@ -64,10 +65,10 @@ public void GivenClassToProxyWithMultiplePropertyValues_WhenBuildingProxy_Return
6465
[Fact]
6566
public void GivenClassWithSomeVirtualProperties_WhenBuildingProxy_ThenOnlyVirtualMembersAreProxied()
6667
{
67-
var proxyBuilder = new ProxyBuilder<Company>(new Dictionary<string, object>()
68+
var proxyBuilder = new ProxyBuilder<Company>(new Dictionary<string, Func<object>>()
6869
{
69-
{"Name", "Vandelay Industries"},
70-
{"EmployeeCount", 100}
70+
{"Name", () => "Vandelay Industries"},
71+
{"EmployeeCount", () => 100}
7172
});
7273

7374
var proxy = proxyBuilder.Build();

TestStack.Dossier/ProxyBuilder.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Collections.Generic;
1+
using System;
2+
using System.Collections.Generic;
23
using System.Linq;
34
using System.Reflection;
45
using NSubstitute;
@@ -11,13 +12,13 @@ namespace TestStack.Dossier
1112
/// <typeparam name="T">The type being proxied</typeparam>
1213
public class ProxyBuilder<T> where T : class
1314
{
14-
private readonly Dictionary<string, object> _properties;
15+
private readonly Dictionary<string, Func<object>> _properties;
1516

1617
/// <summary>
1718
/// Create a proxy builder to proxy the given property values for the type {T}.
1819
/// </summary>
1920
/// <param name="properties"></param>
20-
public ProxyBuilder(Dictionary<string, object> properties)
21+
public ProxyBuilder(Dictionary<string, Func<object>> properties)
2122
{
2223
_properties = properties;
2324
}
@@ -33,7 +34,7 @@ public T Build()
3334
foreach (var property in properties.Where(property => _properties.ContainsKey(property.Name)))
3435
{
3536
if (property.GetGetMethod().IsVirtual)
36-
property.GetValue(proxy, null).Returns(_properties[property.Name]);
37+
property.GetValue(proxy, null).Returns(_properties[property.Name]());
3738
}
3839

3940
return proxy;

TestStack.Dossier/TestDataBuilder.cs

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public abstract class TestDataBuilder<TObject, TBuilder>
1515
where TObject : class
1616
where TBuilder : TestDataBuilder<TObject, TBuilder>, new()
1717
{
18-
private readonly Dictionary<string, object> _properties = new Dictionary<string, object>(StringComparer.InvariantCultureIgnoreCase);
18+
private readonly Dictionary<string, Func<object>> _properties = new Dictionary<string, Func<object>>();
1919
private ProxyBuilder<TObject> _proxyBuilder;
2020

2121
/// <summary>
@@ -107,16 +107,30 @@ public TBuilder AsProxy()
107107
/// </summary>
108108
/// <param name="proxy">The proxy object</param>
109109
protected virtual void AlterProxy(TObject proxy) {}
110-
110+
111111
/// <summary>
112112
/// Records the given value for the given property from {TObject} and returns the builder to allow chaining.
113113
/// </summary>
114114
/// <typeparam name="TValue">The type of the property</typeparam>
115115
/// <param name="property">A lambda expression specifying the property to record a value for</param>
116-
/// <param name="value">The builder so that other method calls can be chained</param>
116+
/// <param name="value">The value to set the property to</param>
117+
/// <returns>The builder so that other method calls can be chained</returns>
117118
public virtual TBuilder Set<TValue>(Expression<Func<TObject, TValue>> property, TValue value)
118119
{
119-
_properties[Reflector.GetPropertyNameFor(property)] = value;
120+
_properties[Reflector.GetPropertyNameFor(property)] = () => value;
121+
return this as TBuilder;
122+
}
123+
124+
/// <summary>
125+
/// Records a given value provider for the given property from {TObject} and returns the builder to allow chaining.
126+
/// </summary>
127+
/// <typeparam name="TValue">The type of the property</typeparam>
128+
/// <param name="property">A lambda expression specifying the property to record a value for</param>
129+
/// <param name="factory">A method which produces instances of {TValue} for the property.</param>
130+
/// <returns>The builder so that other method calls can be chained</returns>
131+
public virtual TBuilder Set<TValue>(Expression<Func<TObject, TValue>> property, Func<TValue> factory)
132+
{
133+
_properties[Reflector.GetPropertyNameFor(property)] = () => factory() as object;
120134
return this as TBuilder;
121135
}
122136

@@ -129,10 +143,7 @@ public virtual TBuilder Set<TValue>(Expression<Func<TObject, TValue>> property,
129143
/// <returns>The recorded value of the property or an anonymous value for it</returns>
130144
public TValue Get<TValue>(Expression<Func<TObject, TValue>> property)
131145
{
132-
if (!Has(property))
133-
return Any.Get(property);
134-
135-
return (TValue)_properties[Reflector.GetPropertyNameFor(property)];
146+
return (TValue)Get(typeof (TValue), Reflector.GetPropertyNameFor(property));
136147
}
137148

138149
/// <summary>
@@ -144,9 +155,11 @@ public TValue Get<TValue>(Expression<Func<TObject, TValue>> property)
144155
/// <returns></returns>
145156
public object Get(Type type, string propertyName)
146157
{
147-
if (!Has(propertyName))
148-
return Any.Get(type, propertyName);
149-
return _properties[propertyName];
158+
Func<object> factory;
159+
if (_properties.TryGetValue(propertyName, out factory))
160+
return factory();
161+
162+
return Any.Get(type, propertyName);
150163
}
151164

152165
/// <summary>

0 commit comments

Comments
 (0)