Basic builder methods

The base class of the builders (including the generic Builder<T> implementation) contains a number of methods that you can make use of both internally when creating a custom builder, and externally when calling methods on a builder instance.

Set

/// <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 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)
  
/// <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)

The Set methods allow you to store a value internally within the builder so it can be retrieved again. This is the core part of the implementation of the Test Data Builder pattern. Usually you would need to create a private property to hold every intermediate value you wanted to track in your test data builder, but this gets very tedious and adds a lot of noise to the builder. The Set methods allow you to store a type-safe value against a public property of the object you are building.

While you won't always want to store a value that corresponds to a public property, we find that over 90% of the time this applies and so this has a huge effect to reducing noise and making it easier to quickly get up and running with a test data builder class.

There are two Set overloads - one that takes a value and another that takes a lambda expression. The latter is useful when you want something lazily evaluated or you are calling Set as part of building a list of objects and want a different value for each object generated. The lambda expression takes an anonymous value fixture that allows you to supply an anonymous value that shares the fixture with the builder.

Note: Nested property names aren't supported - whatever the last property is in the chain is the property name that will be stored against. If this is something you need feel free to contribute.

The Set methods return the test data builder instance so they can be used for fluent chaining.

Here are some examples:

// In a CustomerBuilder
public CustomerBuilder WithFirstName(string firstName)
{
    return Set(x => x.FirstName, firstName);
}

// As part of a Builder<T> call
var student = Builder<StudentViewModel>.CreateNew()
    .Set(x => x.StudentId, 12884352)
    .Build();

// Evaluated as part of building a list
var studentNumber = 1000000;
var students = Builder<StudentViewModel>.CreateListOfSize(10)
    .TheFirst(1).Set(x => x.FirstName, "John")
    .All().Set(x => x.StudentId, _ => studentNumber += 10)
    .BuildList();

// Use the anonymous value fixture from the builder
var student = Builder<StudentViewModel>.CreateNew()
    .Set(x => x.FirstName, any => any.FirstName())
    .Build();

Has

/// <summary>
/// Returns whether or not there is currently an explicit value recorded against the given property from {TObject}.
/// </summary>
/// <typeparam name="TValue">The type of the property</typeparam>
/// <param name="property">A lambda expression specifying the property to retrieve the recorded value for</param>
/// <returns>Whether or not there is a recorded value for the property</returns>
protected bool Has<TValue>(Expression<Func<TObject, TValue>> property)
  
/// <summary>
/// Returns whether or not there is currently an explicit value recorded against the given property from {TObject}.
/// </summary>
/// <param name="propertyName">A string specifying the name of the property to retrieve the recorded value for</param>
/// <returns>Whether or not there is a recorded value for the property</returns>
protected bool Has(string propertyName)

The Has methods return whether or not an explicit value has been set using one of the Set methods. There is a lambda expression version that takes a property from the object being built and there is a string version that simply takes the property name.

Get / GetOrDefault

/// <summary>
/// Gets the recorded value for the given property from {TObject} or an anonymous
///  value if there isn't one specified.
/// </summary>
/// <typeparam name="TValue">The type of the property.</typeparam>
/// <param name="property">A lambda expression specifying the property to retrieve the recorded value for</param>
/// <returns>The recorded value of the property or an anonymous value for it</returns>
public TValue Get<TValue>(Expression<Func<TObject, TValue>> property)

/// <summary>
/// Gets the recorded value for the given property from {type} or an anonymous
///  value if there isn't one specified.
/// </summary>
/// <param name="type">The type of the property.</param>
/// <param name="propertyName">The property name.</param>
/// <returns></returns>
public object Get(Type type, string propertyName)

/// <summary>
/// Gets the recorded value for the given property from {TObject} or if no
/// value has been recorded the default value for {TValue}.
/// </summary>
/// <typeparam name="TValue">The type of the property</typeparam>
/// <param name="property">A lambda expression specifying the property to retrieve the recorded value for</param>
/// <returns>The recorded value of the property or teh default value for {TValue} if no value recorded</returns>
public TValue GetOrDefault<TValue>(Expression<Func<TObject, TValue>> property)

The Get methods allow you to retrieve values that have been set using the Set methods. There are three variants:

  • One that takes a lambda expression identifying a property on the object being built, that returns a strongly-typed value corresponding to that property, and if no explicit value has been set using Set for that property it generates an anonymous value
  • One that takes the type and (string) name of the property to return a value for, or if a value hasn't been explicity set against that property using Set then it generates an anonymous value
  • One that takes a lambda expression identifying a property on the object being built, that returns a strongly-typed value corresponding to that property, and if no explicit value has been set using Set for that property it returns the default value for that type

Examples:

var builder = Builder<StudentViewModel>.CreateNew();

builder.Get(x => x.FirstName); // "John" (or another anonymous value via Any.FirstName()
builder.Get(typeof(string), "FirstName"); // "John" (or another anonymous value via Any.FirstName()
builder.GetOrDefault(x => x.FirstName); // null

builder.Set(x => x.FirstName, "Joe");
builder.Get(x => x.FirstName); // "Joe"
builder.Get(typeof(string), "FirstName"); // "Joe"
builder.GetOrDefault(x => x.FirstName); // "Joe"

ListBuilder

/// <summary>
/// The list builder instance (if this is a a list builder proxy).
/// </summary>
public ListBuilder<TObject, TBuilder> ListBuilder { get; }

If the builder instance is a list builder proxy object then calling ListBuilder will return the List Builder instance. You would typically only need this in more advanced scenarios e.g. you had an extension method on ListBuilder or some other method requiring it. Ordinarily, you would convert the proxy to a list of real objects using the BuildList method.

IsListBuilderProxy

/// <summary>
/// Returns whether or not the builder instance is a proxy for building a list or an actual builder instance.
/// </summary>
/// <returns>Whether or not the instance is a list builder proxy</returns>
public virtual bool IsListBuilderProxy()

Allows you to check if the builder instance is a list builder proxy object or a real builder instance.

Any

/// <summary>
/// Generate anonymous data using this fixture - one instance per builder instance.
/// </summary>
public AnonymousValueFixture Any { get; }

You can access the anonymous value fixture via the Any property.

BuildUsing

/// <summary>
/// Builds the object from this builder using an <see cref="IFactory"/>.
/// </summary>
/// <typeparam name="TFactory">The factory to use to build the object</typeparam>
/// <returns>The built object</returns>
protected TObject BuildUsing<TFactory>()
    where TFactory : IFactory, new()

Can be called from within your custom builder to choose an automatic construction factory. This replaces the need to call the new operator yourself.

Note: There are a few assumptions/limitations (as documented) with the default construction factories that you need to be aware of, but you can create your own auto construction factories too.

AsProxy

/// <summary>
/// Return an NSubstitute proxy object when .Build() is called rather than a real object.
/// </summary>
/// <returns>The builder so that other method calls can be chained</returns>
public TBuilder AsProxy()

Allows you to build an NSubstitute proxy object rather than a real object. See Creating proxy objects.

AlterProxy

/// <summary>
/// Alter the proxy object just after it has been built and before it's returned from .Build().
/// This allows you to add any .Returns() values that are more complex than the public properties that are proxied by default.
/// </summary>
/// <param name="proxy">The proxy object</param>
protected virtual void AlterProxy(TObject proxy)

Override it in your custom builders to allow you to set .Returns values on the NSubstitute proxy that gets generated if you use AsProxy where you need more than just return values on the public property getters (which is added by default).

CreateListOfSize

/// <summary>
/// Creates an list builder expression that allows you to create a list of entities.
/// You can call .First(x), .Last(x), etc. methods followed by chained builder method calls.
/// When you are done call .BuildList() to get the list of entities.
/// </summary>
/// <param name="size">The size of list</param>
/// <returns>The list builder for a list of {TBuilder} of the specified size</returns>
public static ListBuilder<TObject, TBuilder> CreateListOfSize(int size)

Static method on your builder class (or the generic class) to allow you to create a lists of objects very tersely.

GetChildBuilder

/// <summary>
/// Creates (and optionally modifies) a child builder class of this builder; sharing the anonymous value fixture.
/// </summary>
/// <typeparam name="TChildObject">The type of the child object being built</typeparam>
/// <typeparam name="TChildBuilder">The type of the builder for the child object being built</typeparam>
/// <param name="modifier">An optional modifier lambda expression with fluent builder method calls for the child builder</param>
/// <returns>The instance of the child builder</returns>
protected virtual TChildBuilder GetChildBuilder<TChildObject, TChildBuilder>(Func<TChildBuilder, TChildBuilder> modifier = null)
    where TChildObject : class
    where TChildBuilder : TestDataBuilder<TChildObject, TChildBuilder>, new()

Allows you to tersely create a value to store in your builder by using another builder class (with optional configuration), while sharing the anonymous value fixture.

Example:

public StudentBuilder WithClass(Func<ClassBuilder, ClassBuilder> modifier = null)
{
  return Set(x => x.CurrentClass, GetChildBuilder<AcademicClass, ClassBuilder>(modifier));
}