Announcing TestStack.Dossier v3.0

We're pleased to announce the release of TestStack.Dossier version 3.0. We've been working on some exciting changes to make the library even more useful and even easier to use. As usual you can grab the changes on NuGet.

Builder class - generic test data builder

If you are building domain entities, or other important classes, having a custom builder class with intention-revealing methods like WithFirstName provides terseness (by avoiding lambda expressions) as well as allowing the builder class to start forming documentation about the usage of that object. Sometimes though, you just want to build a class without that ceremony. Typically, we find that this applies for view models and DTOs.

To that end we have created a generic implementation of the Test Data Builder class with syntax that is very similar in both form and function to what NBuilder provides, e.g.:

var vm = Builder<StudentViewModel>.CreateNew()
  .Set(x => x.FirstName, "Pi")
  .Set(x => x.LastName, "Lanningham")
  .Set(x => x.EnrollmentDate, new DateTime(2000, 1, 1))
  .Build();

var i = 0;
var studentViewModels = Builder<StudentViewModel>.CreateListOfSize(5)
  .TheFirst(1).Set(x => x.FirstName, "First")
  .TheNext(1).Set(x => x.LastName, "Next Last")
  .TheLast(1).Set(x => x.LastName, "Last Last")
  .ThePrevious(2).With(b => b.Set(x => x.LastName, "last" + (++i).ToString()))
  .All().Set(x => x.EnrollmentDate, _enrollmentDate)
  .BuildList();

By default, the longest constructor of the class you specify will be called and then all properties (with public and private setters) will be set with values you specified (or anonymous values if none were specified). The behaviour of this can be modified though.

Feel free to check out the implementation (it's incredibly simple) and the documentation for this feature.

Automatic object construction support

Previously you would be forced to override the BuildObject method when extending TestDataBuilder. You would then need to call the constructor of your object and pass in the values using Get(...) or otherwise. While this is useful for complex objects, for simpler objects it feels like boilerplate since you are typically doing a 1:1 relationship between constructor parameters and properties (via Get).

To that end we have created some factories that use the builder instance to intelligently instantiate your object by convention. You can invoke this via the BuildUsing method, e.g.:

public class CustomerBuilder : TestDataBuilder<Customer, CustomerBuilder>
{
  ...

  protected override Customer BuildObject()
  {
    return BuildUsing<CallConstructorFactory>();
  }
}

If you don't override the BuildObject method then by default it will use the PublicPropertySettersFactory, which calls the longest constructor with builder values (or anonymous values if none set) based on case-insensitive match of constructor parameter names against property names and then calls the setter on all properties with public setters with builder values (or anonymous values if none set).

There are other factories available and these are explained in the documentation .

Breaking changes

There was a breaking change in this version to the signature of IAnonymousValueSupplier in order to allow for the implementation of the automatic object construction support. We anticipate this won't affect most users, but in light of the fact there was a breaking change we have bumped the version number to 3.0. You can consult the breaking changes documentation for more information.

Documentation update

We have started to better document Dossier with this release and while there is still a ways to go to provide the comprehensiveness of documentation we would like, the majority of the features in Dossier are now explored in the documentation

Changelog