Introducing NBuilder

Posted on February 1, 2009. Filed under: .NET, Automated Testing, C#, Functional Testing, NBuilder, Unit Testing |

UPDATE: 06 June 2009 – This post is based on a proof of concept and as such the syntax has changed slightly. Please see the project page for up to date documentation:

When I’m writing tests I frequently need to create some quick test data either for using as the result of a mock object or perhaps for inserting into a database and then either running an automated functional test or an automated browser / acceptance test with it. I want to be able to create it in my test or in the setup for a test and I want to be able to do it very quickly.

The goal

I want to be able to say something like this:

1. Create a list of 100 categories

2. Create a list of 100 products, and give them all between 1 and 5 categories each.

Implementation

Consider the following simple model:

class_diagram1

What I usually find myself doing is having a class such as ProductBuilder and giving it static methods such as:

fig01-product_builder

Perhaps also with a few ‘WithAbc(xyz)’ methods to set certain properties. However as you can imagine you soon end up with loads of builder classes and loads of methods.

I decided there had to be a better way. I had a quick search on the web but I couldn’t find anything that looked like it would do the job. I wanted something with a very fluent interface where I could almost write the code by saying something like Create 100 Products, each with a tax type of VAT, and each in some categories. I couldn’t find anything like this, so I decided to create a library myself.

Builder<T>

I started off with a class Builder<T>Then I started by coming up with a generic way to create a list:

fig02

I thought that the properties should be set to something by default using some reflection and decided I wasn’t really too bothered about what the values of most of the properties were so i decided to to set every string to its name, and append its one-based index to it. So for example the first object’s Title would be set to Title1, the second Title2 etc, etc. All the integers and decimals etc would be set to 1,2,3,4; 1.0, 2.0, 3.0, 4.0 etc, etc. So using this you can easily make a list of products each with their basic properties populated.

However, what if you want some of them – the first 10 to have a different title? I added this where syntax to cope with that:

fig03

Ok cool – but what if you also want those same ten to have a specific value for the QuantityInStock property:

fig04

How about you want to give them a random quantity, between 1 and 2000? This is where the Generate class comes in:

fig05

How about if you want the next ten after it to have different properties still:

fig06

What about giving a random 50 the quantity of 1? (Perhaps you could test some stock alerting functionality with this for instance)

fig07

The ‘Pick’ Class

Ok you get the idea. That’s the easy kind of thing out of the way. How about relations? What if you want to add categories to your products? What if you want to add different categories and a different number of categories to each product?

I came up with the ‘Pick’ class to do this.

fig08

I think that reads pretty well, if I was coming to read someone’s test set up, I could see straight away from that what they were doing.

Now do what you want with them – return them in a mocked object or if you’re doing a functional/integration or acceptance test you could use your repository / data layer to save them to the database:

fig08_1

Test data inserted and it only took a few lines of simple easy to read code. Job done, now you can get on and write your tests.

Adding NBuilder to your functional test

fig093

Download the binary

Download NBuilder Binary from Google Code

Features I haven’t mentioned here

  1. The method HaveDoneToThem(Action<T>). As the name suggests this allows you to call a method on each object in the same way as you use Have(). You could use this to add a value object to each of the list elements.
  2. There is also a CreateNew() method for creating a single object.

Please bear in mind…

Please note that this is only one step up from a proof of concept at the moment so if you try it out please bear in mind:

  1. While it has been unit tested, and everything I have described here does work, it has only been tested using this syntax. For example I have no idea what would happen if you did a Have() before having done a WhereTheFirst() or WhereRandom(). You might get an exception.
  2. When the initial object generation happens, it supports most simple data types int, string, long, DateTime etc, but it doesn’t support unsigned types yet. (No particular reason other than I just haven’t bothered to add them in yet)
  3. The Generate class only support ints and decimals. And it doesn’t support decimals all that well either! You can only say generate numbers between two integers at the moment.

As I use this tool in real projects over the next few weeks I will add to it, make it more robust and do another posting and probably get the source code up very soon too.

Comments and suggestions

I’d be interested to hear any comments, suggestions or if anyone knows if there is already something out there that does what NBuilder does.

p.s. – Sorry – I couldn’t think of anything more imaginative than NBuilder!

Advertisements

Make a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

6 Responses to “Introducing NBuilder”

RSS Feed for ShouldBeAbleTo Comments RSS Feed

This looks really interesting. Keep us up to date on how you progress with your testing and looking forward to seeing the source. I’m planning on giving it a go on a prototype project.

You probably also saw this:

http://svn.stormwindproject.org/svn/Stormwind.PowerFixtures/

They appear to have some sort of documentation up but the server was down last time I checked.

http://using.stormwindproject.org:8081/display/powerfixtures/Home

You can still poke around in the tests though.

Kevin – thanks very much for taking the time to comment.

I had hoped to have the source code posted by now but I’ve been quite busy lately. The fact that someone has actually read this and has given positive feedback has spurred me on so I will make a big effort to do it this weekend!

Yes, I have seen PowerFixtures and it seems to do pretty much almost the same thing but in different ways. (I actually know its creator, a very talented developer named Bernardo. We were both working at the same site for a while).

However, I wanted something with a very readable interface. I wanted to make it so the developer doesn’t have to think at all when reading or writing the code.

While PowerFixtures has some good features and is probably more mature I’m not sure it offers the same fluency that you get with NBuilder.

Thanks again. I’ll get that code posted asap!

Gareth,

So I had a chance to tinker a bit with NBuilder in my prototype project and it’s been very cool. Regarding PowerFixtures, my feelings are basically the same. Seemed pretty powerful but I liked the API on NBuilder much more.

One issue I ran into was where I needed some immutable objects generated (properties set through c’tor). It didnt seem to me that there was anyway to handle that situation with NBuilder at this point.

Would maybe be cool to have a WithConstructor method on ListBuilder to have instances created with a specific constructor. This is pure speculation as I’m not sure if this is even possible but I wonder if the ctor could somehow be specified with a lambda expression. There is a NewExpression class that might allow you to loop over the ctor args and fill them in the using one of your naming strategies. Anyway, just a thought.

Thanks and great work!

Hi Kevin

Thanks again for your input and for trying it out.

I have posted the code on google code now:
http://code.google.com/p/nbuilder/source/browse and there’s also a slightly newer binary release. Please note the code is fairly rough and ready, it’s little more than a day’s work but it’s a start and hopefully will grow into something decent. Feel free to contribute if you wish, I can set you up with access!

Regarding constructor args, no you’re right at the moment there’s no way of doing it. The only thing that comes close is using the prototype / based on option eg:

var prototype = new Category(arg1, arg2, arg3);
Builder.CreateListOfSize(2, prototype).List;

(nb: I plan to improve this interface so you could write Builder.UsingPrototype(prototype).CreateListOf….)

That’s a great suggestion to have a WithConstructor() method, I’m not sure of the best place to put it though, I guess before you call the CreateListOfSize() / CreateNew() method? ie

Builder.WithConstructor(arg1, arg2).CreateListOfSize(10).Wherexyz

Also, yeah good idea to use expressions. What I’d really like to do, if it would be possible, is to keep the same interface but instead of doing the building on the fly like it does now, make it build up an expression tree and then execute it at the end. I’m sure this would open up more possibilities.

I have lots of ideas for it, one thing I’d really like to include is the ability to generate a random string based on a regular expression or include words from a pre-defined list or dictionary. Visual studio team system database edition does this and it’s really cool, however you can’t run it from your code or as part of a build etc, so it would be cool to add this kind of feature to NBuilder.

Hi Gareth,

I only just found the link for this but I’ll definitely take a look. Peeking at your functional tests suggests you are wandering a similar path. I’ll be interested to see where you end up,

Hi Ian

Thanks very much for your comment – please give it two weeks and then take a look. The reason being I’ve got a big load of fundamental changes I need to finish and check in. My contract is coming to an end next week and have been doing incredibly long hours on the project I’m working on so I haven’t had any time to finish it!

I’ll be finishing it off and re-releasing w/c 6 April so check back shortly after then to see the new version!

Thanks

Gareth


Where's The Comment Form?

Liked it here?
Why not try sites on the blogroll...

%d bloggers like this: