#TIL: Using NBuilder to Generate Objects

Often when writing unit or integration tests, the boilerplate code of creating test objects and collections to pass around can be a bit tedious. That’s where NBuilder comes in!

Let’s say you’re mocking out a data service that would return you a list of customers, with which your unit test depends on. Normally you’d probably write something like this (using FakeItEasy for mocks):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var customerList = new List<Customer>() {
  new Customer() {
      ID = 1,
      Name = "Chad",
      Country = "Canada"
  },
  new Customer() {
      ID = 2,
      Name = "El Chado",
      Country = "Mexico"
  },
  new Customer() {
      ID = 3,
      Name = "Chadtasico",
      Country = "Spain"
  }
};
A.CallTo(() => fakeCustomerService.GetCustomers()).Returns(customerList);

This is just a basic example – if you need to test complicated billing logic, your customer objects (and other related objects) are probably going to be a lot more verbose than that. Then your unit tests end up being 200+ lines of code and really hard to navigate through for other developers. Using NBuilder, we can automate a lot of this process and reduce the number of lines required to generate test data. For example:

1
var customer = Builder<Customer>.CreateNew().Build();

…would generate an object for us like this:

1
{ ID: 1, Name: "Name1", Country: "Country1" }

As you can see, it automatically generates property values for us based on the property’s name. If we want to set specific properties:

1
Builder<Customer>.CreateNew().With(c => c.Name = "Chad").Build();

This allows us to specify individual properties’ values, and you can define additional clauses by appending .With methods as many times as you want. You can also call methods on your generated objects with the Do method.

1
2
3
var customer = Builder<Customer>.CreateNew().Build();
var salesperson = Builder<Salesperson>.CreateNew()
  .Do(s => s.AddCustomer(customer)).Build();

One of my favorite features is creating lists of data:

1
var customerList = Builder<Customer>.CreateListOfSize(3).Build();

And setting properies for objects in that generated list:

1
2
3
4
5
6
var customerList = Builder<Customer>.CreateListOfSize(3)
  .All().With(c => c.Name = "Chad").Build();
//or specific objects
customerList = Builder<Customer>.CreateListOfSize(3)
  .TheFirst(1).With(c => c.Country = "Canada")
  .TheLast(2).With(c => c.Country = "Not Canada").Build();

This is all fine and dandy for unit tests, but what about integration tests? If you want to do some database setup to define a state before running a test, you usually have to manually manipulate your data layer or database to create that state. With Builder, you can define a Persist method instead.

1
2
3
4
5
BuidlerSetup.SetCreatePersistanceMethod<Customer>(c => MyDataLayer.SaveCustomer(c));
Builder<Customer>.CreateNew().Persist();
//or
BuilderSetup.SetCreatePersistenceMethod<IList<Customer>>(c => MyDataLayer.SaveCustomers(c));
Builder<Customer>.CreateListOfSize(3).Persist();

Using the NBuilder library (available via NuGet) you can cut out all that boilerplate test setup code and focus on what’s really important – the actual test.

Comments