Skip to content

Adds a Set overload which takes a lambda factory method #36

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 21, 2015
Merged
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
11 changes: 11 additions & 0 deletions CONTRIBUTOR_GUIDELINES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Contributor Guidelines
======================

Hi! Thank you for your interest in contributing to this open source library!
We ask that you follow the following style guidelines when submitting pull
requests, to keep the code consistent and maintainable.

- Do not put an if clause and it's statement on the same line: separate them
with a new-line and indent accordingly.

(This file will be expanded as more guidelines are established by the maintainer)
29 changes: 28 additions & 1 deletion TestStack.Dossier.Tests/BuildTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Shouldly;
using System.Collections.Generic;
using Shouldly;
using TestStack.Dossier.Tests.TestHelpers.Builders;
using TestStack.Dossier.Tests.TestHelpers.Objects.Entities;
using Xunit;
Expand Down Expand Up @@ -47,6 +48,32 @@ public void GivenBuilder_WhenCallingSetExplicitly_ShouldOverrideValues()
customer.YearJoined.ShouldBe(2014);
}

[Fact]
public void GivenBuilder_WhenCallingSetWithLambda_ShouldInvokeEachTime()
{
int counter = 2014;
var builder = new CustomerBuilder()
.Set(x => x.FirstName, "Pi")
.Set(x => x.LastName, "Lanningham")
.Set(x => x.YearJoined, () => counter++);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also wanted to provide an overload that would take a lambda Func from TObj to TValue, so that you could base your value on the partially constructed object (i.e. make sure that AmountPaid was less than AmountOwed, or something),but that would have required too much internal structuring, so I left it for another day.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be too hard to do the partially constructed object, you could do one that takes the builder so you can use a Get call though?


var customerA = builder.Build();
var customerB = builder.Build();

customerA.YearJoined.ShouldBe(2014);
customerB.YearJoined.ShouldBe(2015);

List<Customer> customerList = CustomerBuilder.CreateListOfSize(10)
.All()
.Set(x => x.YearJoined, () => counter++);
int newCounter = 2016;
foreach (var c in customerList)
{
c.YearJoined.ShouldBe(newCounter++);
}

}

[Fact]
public void GivenBasicBuilder_WhenCallingBuildImplicitly_ThenReturnAnObject()
{
Expand Down
25 changes: 13 additions & 12 deletions TestStack.Dossier.Tests/ProxyBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class ProxyBuilderTests
[Fact]
public void GivenClassToProxyWithNoProperties_WhenBuildingProxy_ReturnAClassWithNoReturnsValuesSet()
{
var proxyBuilder = new ProxyBuilder<Customer>(new Dictionary<string, object>());
var proxyBuilder = new ProxyBuilder<Customer>(new Dictionary<string, Func<object>>());

var proxy = proxyBuilder.Build();

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

var proxy = proxyBuilder.Build();

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

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

var proxy = proxyBuilder.Build();

proxy.FirstName.ShouldBe("FirstName");
proxy.FirstName.ShouldBe("FirstName" + nonce);
proxy.LastName.ShouldBe(string.Empty);
proxy.YearJoined.ShouldBe(0);
}

[Fact]
public void GivenClassToProxyWithMultiplePropertyValues_WhenBuildingProxy_ReturnAClassWithReturnValueSet()
{
var proxyBuilder = new ProxyBuilder<Customer>(new Dictionary<string, object>
var proxyBuilder = new ProxyBuilder<Customer>(new Dictionary<string, Func<object>>
{
{ "FirstName", "FirstName" },
{ "LastName", "LastName" },
{ "YearJoined", 1 },
{ "FirstName", () => "FirstName" },
{ "LastName", () => "LastName" },
{ "YearJoined", () => 1 },
}
);

Expand All @@ -64,10 +65,10 @@ public void GivenClassToProxyWithMultiplePropertyValues_WhenBuildingProxy_Return
[Fact]
public void GivenClassWithSomeVirtualProperties_WhenBuildingProxy_ThenOnlyVirtualMembersAreProxied()
{
var proxyBuilder = new ProxyBuilder<Company>(new Dictionary<string, object>()
var proxyBuilder = new ProxyBuilder<Company>(new Dictionary<string, Func<object>>()
{
{"Name", "Vandelay Industries"},
{"EmployeeCount", 100}
{"Name", () => "Vandelay Industries"},
{"EmployeeCount", () => 100}
});

var proxy = proxyBuilder.Build();
Expand Down
9 changes: 5 additions & 4 deletions TestStack.Dossier/ProxyBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using NSubstitute;
Expand All @@ -11,13 +12,13 @@ namespace TestStack.Dossier
/// <typeparam name="T">The type being proxied</typeparam>
public class ProxyBuilder<T> where T : class
{
private readonly Dictionary<string, object> _properties;
private readonly Dictionary<string, Func<object>> _properties;

/// <summary>
/// Create a proxy builder to proxy the given property values for the type {T}.
/// </summary>
/// <param name="properties"></param>
public ProxyBuilder(Dictionary<string, object> properties)
public ProxyBuilder(Dictionary<string, Func<object>> properties)
{
_properties = properties;
}
Expand All @@ -33,7 +34,7 @@ public T Build()
foreach (var property in properties.Where(property => _properties.ContainsKey(property.Name)))
{
if (property.GetGetMethod().IsVirtual)
property.GetValue(proxy, null).Returns(_properties[property.Name]);
property.GetValue(proxy, null).Returns(_properties[property.Name]());
}

return proxy;
Expand Down
35 changes: 24 additions & 11 deletions TestStack.Dossier/TestDataBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,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>(StringComparer.InvariantCultureIgnoreCase);
private readonly Dictionary<string, Func<object>> _properties = new Dictionary<string, Func<object>>();
private ProxyBuilder<TObject> _proxyBuilder;

/// <summary>
Expand Down Expand Up @@ -107,16 +107,30 @@ public TBuilder AsProxy()
/// </summary>
/// <param name="proxy">The proxy object</param>
protected virtual void AlterProxy(TObject proxy) {}

/// <summary>
/// Records the given value for the given property from {TObject} and returns the builder to allow chaining.
/// </summary>
/// <typeparam name="TValue">The type of the property</typeparam>
/// <param name="property">A lambda expression specifying the property to record a value for</param>
/// <param name="value">The builder so that other method calls can be chained</param>
/// <param name="value">The value to set the property to</param>
/// <returns>The builder so that other method calls can be chained</returns>
public virtual TBuilder Set<TValue>(Expression<Func<TObject, TValue>> property, TValue value)
{
_properties[Reflector.GetPropertyNameFor(property)] = value;
_properties[Reflector.GetPropertyNameFor(property)] = () => value;
return this as TBuilder;
}

/// <summary>
/// Records a given value provider for the given property from {TObject} and returns the builder to allow chaining.
/// </summary>
/// <typeparam name="TValue">The type of the property</typeparam>
/// <param name="property">A lambda expression specifying the property to record a value for</param>
/// <param name="factory">A method which produces instances of {TValue} for the property.</param>
/// <returns>The builder so that other method calls can be chained</returns>
public virtual TBuilder Set<TValue>(Expression<Func<TObject, TValue>> property, Func<TValue> factory)
{
_properties[Reflector.GetPropertyNameFor(property)] = () => factory() as object;
return this as TBuilder;
}

Expand All @@ -129,10 +143,7 @@ public virtual TBuilder Set<TValue>(Expression<Func<TObject, TValue>> property,
/// <returns>The recorded value of the property or an anonymous value for it</returns>
public TValue Get<TValue>(Expression<Func<TObject, TValue>> property)
{
if (!Has(property))
return Any.Get(property);

return (TValue)_properties[Reflector.GetPropertyNameFor(property)];
return (TValue)Get(typeof (TValue), Reflector.GetPropertyNameFor(property));
}

/// <summary>
Expand All @@ -144,9 +155,11 @@ public TValue Get<TValue>(Expression<Func<TObject, TValue>> property)
/// <returns></returns>
public object Get(Type type, string propertyName)
{
if (!Has(propertyName))
return Any.Get(type, propertyName);
return _properties[propertyName];
Func<object> factory;
if (_properties.TryGetValue(propertyName, out factory))
return factory();

return Any.Get(type, propertyName);
}

/// <summary>
Expand Down