// Arrange Act Assert

Jag Reehal on Agile Development, ASP.NET MVC and all manner of good stuff


How NBuilder Could Help You Write Better .Net Unit Tests

Posted on | March 10, 2010 | No Comments

One of the biggest challenges when creating unit tests is to come up test data. It makes sense having someone other than you test your code, so how about having someone other than you generate the test input for your .Net unit tests.

Data generation tools aren’t new concept and they come in many different forms. When I first saw Red Gate Sql Data Generator a couple of years ago, I thought to myself it’s a shame you need a database because this would have been great for unit and integration tests.

In this blog post I want to show you how NBuilder can be used when unit testing with .Net objects. The NBuilder assembly can be downloaded here http://code.google.com/p/nbuilder/.

In this blog post we will be using the product and category classes below

public class Product
{
    public Product()
    {
        Categories = new List<Category>();
    }

    public Guid Id { get; set; }
    public string Name { get; set; }
    public int Rating { get; set; }
    public decimal Price { get; set; }
    public bool InStock { get; set; }
    public List<Category> Categories { get; set; }

    public override string ToString()
    {
        return String.Format("Id:{0}, Name:{1}, Rating:{2}, Price:{3}, InStock:{4}, Categories:{5}", Id, Name, Rating, Price, InStock, Categories.Count);
    }
}

public class Category
{
    public string Name { get; set; }
}

NBuilder default values

The product class contains a variety of types. When you run the following code to create 10 products

[Test]
public void Should_Create_Ten_Products()
{
    var products = Builder<Product>.CreateListOfSize(10).Build();
    products.Count().ShouldEqual(10);
}

this is the output

Id Name Rating Price InStock Categories Count
00000000-0000-0000-0000-000000000001 Name1 1 1 False 0
00000000-0000-0000-0000-000000000002 Name2 2 2 True 0
00000000-0000-0000-0000-000000000003 Name3 3 3 False 0
00000000-0000-0000-0000-000000000004 Name4 4 4 True 0
00000000-0000-0000-0000-000000000005 Name5 5 5 False 0
00000000-0000-0000-0000-000000000006 Name6 6 6 True 0
00000000-0000-0000-0000-000000000007 Name7 7 7 False 0
00000000-0000-0000-0000-000000000008 Name8 8 8 True 0
00000000-0000-0000-0000-000000000009 Name9 9 9 False 0
00000000-0000-0000-0000-00000000000a Name10 10 10 True 0


  • For strings NBuilder suffixes the index number to the name of the property e.g. Name1
  • For numeric values such as int and decimal the default value is the index number
  • For guids a hexadecimal range is used
  • Boolean values alternate between true and false for each product
  • The categories collection is left empty. This would have been null if we didn’t create a new collection in the constructor of the product class

Changing how NBuilder default values are created

I really like how you can customize NBuilder and use your own convention for creating default values.

For example what if we wanted to change how guids are created.

One way to do this is to inherit from the RandomValuePropertyNamer class and override the GetGuid method as shown below.

public class JagsRandomValuePropertyNamer : RandomValuePropertyNamer
{
    protected override Guid GetGuid(System.Reflection.MemberInfo memberInfo)
    {
        return Guid.NewGuid();
    }
}

After setting the default property namer, all guids are created by calling Guid.NewGuid()

[Test]
public void Product_Should_Have_Guid_Assigned()
{
    BuilderSetup.SetDefaultPropertyNamer(new JagsRandomValuePropertyNamer());

    var product = Builder<Product>
        .CreateListOfSize(10)
        .WhereAll()
            .Have(p => p.Id = Guid.NewGuid())
        .Build();

    product[0].Id.ToString().ShouldNotEqual("00000000-0000-0000-0000-000000000001");
}

Using the WhereAll method to set the InStock to always be true

What if we wanted to change the InStock value to true for all the products in the collection. This can be done using the WhereAll method as shown in the code below

[Test]
public void All_Products_Should_Be_In_Stock()
{
    var products = Builder<Product>
        .CreateListOfSize(10)
        .WhereAll()
            .Have(p => p.InStock = true)
        .Build();

    products.All(p => p.InStock).ShouldBeTrue();
}

Using NBuilder to set parts of a collection

There are two ways you can use Nbuilder to set values in parts of a collection. The first is by using the first or last methods like so

[Test]
public void First_Two_Products_Should_Be_In_Stock()
{
    var products = Builder<Product>
        .CreateListOfSize(10)
        .WhereTheFirst(2)
            .Have(p => p.InStock = true)
        .Build();

    products[0].InStock.ShouldBeTrue();
    products[1].InStock.ShouldBeTrue();
}

the other is to use sections

[Test]
public void Mixture_Of_Products_In_Stock_Using_Sections()
{
    var products = Builder<Product>
        .CreateListOfSize(10)
        .WhereSection(0, 1)
            .Have(p => p.InStock = true)
        .WhereSection(2, 9)
            .Have(p => p.InStock = false)
        .Build();

    products[0].InStock.ShouldBeTrue();
    products[2].InStock.ShouldBeFalse();
}

Using the UniqueRandomList to create unique random lists…

So far we haven’t done anything with the category property.

What if you wanted to build a product collection with each product having a random number of categories?

By calling the HaveDoneToThem and the UniqueRandomList methods we can create a set of products with having different categories to one another

[Test]
public void Products_With_Random_Categories()
{
    var categories = Builder<Category>
        .CreateListOfSize(100)
        .Build();

    var products = Builder<Product>
        .CreateListOfSize(10)
        .WhereAll()
        .HaveDoneToThem(p => p.Categories.AddRange(Pick<Category>.UniqueRandomList(2).From(categories)))
        .Build();

    var productCategoryOne = products[0].Categories[0].Name;
    var productCategoryTwo = products[1].Categories[0].Name;

    productCategoryOne.ShouldNotBeTheSameAs(productCategoryTwo);
}

Extending NBuilder with a Lorem Ipsum string generator

One thing I really like about NBuilder is the ability to extend it.

The code below shows how easy it is to have product names randomly using Lorem Ipsum just by creating a extension method like this

public static class StringExtensions
{
    public const string LoremIpsum = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";

    public static IOperable<Product> HavingRandomLoremIpsumProductName(this IOperable<Product> operable)
    {
        ((IDeclaration<Product>)operable).ObjectBuilder.With(x => x.Name = LoremIpsum.Substring(0, new Random().Next(446)));
        return operable;
    }
}

this can be used to generate products with random names like this

[Test]
public void Products_With_Random_LoremIpsum_Names()
{
    var products = Builder<Product>
        .CreateListOfSize(10)
        .WhereAll()
            .HavingRandomLoremIpsumProductName()
        .Build();

    var nameOfProductOne = products[0].Name;
    var nameOfProductTwo = products[1].Name;

    nameOfProductOne.ShouldNotBeTheSameAs(nameOfProductTwo);
}

Jag Reehal’s Final Thought on ‘How NBuilder Could Help You Write Better .Net Unit Tests’

I think frameworks like NBehave could really have a big impact on how you go about having to create test data. The fluent interface is fantastic and it’s so easy to customize.

NBuilder contains a lot more features than I have covered in this post so if you like what you’ve seen make sure you check out the NBuilder documentation.

For the future I’m hoping Fluent NHibernate and NBuilder could work together. For example when you define class maps in Fluent NHibernate you can specify the length of string column. If NBuilder could use information like this when generating data that would really be something special.

How To Create Heat Maps In Sql Server Reporting Services

Posted on | February 8, 2010 | No Comments

Recently I’ve been doing some work with Microsoft Sql Server Reporting Services. One of the tasks I was given was to create a report with a heat map, which means you transform a report that looks like this

Plain Report

to something that looks like this

Bobs Heat Map Report

As you can see the a heat map is excellent way to visualize data.

This was done without the use of any plugins. I implemented the heat map in Reporting Services by following Bob Meyers excellent solution in his ‘Add Excel-like “color scale” conditional formatting to your reports‘ blog post.

Exporting to Excel

One of the requirements for my work was for users to be able to export the report into Microsoft Excel. Unfortunately it was at this point Bob’s solution didn’t work out for me. The problem was I was getting cells with a black background color as shown below.

Errors Exporting To Excel

So I came up with an alternative solution.

An Alternative Sql Server Reporting Services Heat Map Generator

So instead of using hex codes for the color like Bob does, I wanted to play it safe and use Microsoft colors i.e. those in the System.Drawing library.

The code below shows the GetHeatmapColor function which takes in three arguments and returns a string for the color

Public Class SqlReportingServicesHeatMapGenerator
    Public Function GetHeatmapColor(ByVal textBoxValue, ByVal minDataSetValue, ByVal maxDataSetValue) As String
        Dim colours As String() = New String() {"Green", "LimeGreen", "Yellow", "Orange", "OrangeRed", "Red"}

        If textBoxValue = 0 Then
            Return colours(0)
        End If

        If minDataSetValue = maxDataSetValue Then
            Return colours(0)
        End If

        If textBoxValue > maxDataSetValue Then
            Return colours(colours.Length - 1)
        End If

        Dim divider As Integer = (maxDataSetValue - minDataSetValue + 1) / 5
        Dim index As Integer = textBoxValue / divider
        GetHeatmapColor = colours(index)

    End Function
End Class

This function can be unit tested like this. Yes I know this falls a long way from 100% test coverage, but this is just an example ;)

Imports NUnit.Framework

<TestFixture()> _
Public Class When_Getting_The_Fill_Color
    Private _heatMapGenerator As New SqlReportingServicesHeatMapGenerator()
    <Test()> _
    Public Sub Should_Return_Green_For_Zero()
        Dim result = _heatMapGenerator.GetHeatmapColor(0, 1, 100)
        Assert.AreEqual("Green", result)
    End Sub

    <Test()> _
    Public Sub Should_Return_Green_For_Lowest_Value()
        Dim result = _heatMapGenerator.GetHeatmapColor(1, 1, 100)
        Assert.AreEqual("Green", result)
    End Sub

    <Test()> _
    Public Sub Should_Return_Red_For_Highest_Value()
        Dim result = _heatMapGenerator.GetHeatmapColor(100, 1, 100)
        Assert.AreEqual("Red", result)
    End Sub

    <Test()> _
    Public Sub Should_Return_Green_If_All_Values_Are_The_Same()
        Dim result = _heatMapGenerator.GetHeatmapColor(1, 1, 1)
        Assert.AreEqual("Green", result)
    End Sub

    <Test()> _
    Public Sub Should_Return_Red_Even_If_Cell_Value_Is_Greater_Than_The_Maximum()
        Dim result = _heatMapGenerator.GetHeatmapColor(1164, 1, 896)
        Assert.AreEqual("Red", result)
    End Sub
End Class

Implementing The Solution

The colors on the report are shown using the fill property of a text box and an expression to determine what the fill color should be. Follow the steps below to create a heat map in Reporting Services using either Report Builder or Visual Studio.

First create a data source and dataset (we will not be connecting to any databases). Right click on the dataset and select query

Right click on the dataset and select query

In the query for the dataset paste in the sql below

DECLARE @LogTable TABLE (WebServer VARCHAR(10),[Hour] TINYINT, NumberOfUsers INT)
INSERT INTO @LogTable VALUES ('WebServer1',0,0)
INSERT INTO @LogTable VALUES ('WebServer1',1,2)
INSERT INTO @LogTable VALUES ('WebServer1',2,4)
INSERT INTO @LogTable VALUES ('WebServer1',3,6)
INSERT INTO @LogTable VALUES ('WebServer1',4,8)
INSERT INTO @LogTable VALUES ('WebServer1',5,10)
INSERT INTO @LogTable VALUES ('WebServer1',6,12)
INSERT INTO @LogTable VALUES ('WebServer1',7,14)
INSERT INTO @LogTable VALUES ('WebServer1',8,16)
INSERT INTO @LogTable VALUES ('WebServer1',9,18)
INSERT INTO @LogTable VALUES ('WebServer1',10,20)
INSERT INTO @LogTable VALUES ('WebServer1',11,22)
INSERT INTO @LogTable VALUES ('WebServer1',12,24)
INSERT INTO @LogTable VALUES ('WebServer1',13,22)
INSERT INTO @LogTable VALUES ('WebServer1',14,21)
INSERT INTO @LogTable VALUES ('WebServer1',15,20)
INSERT INTO @LogTable VALUES ('WebServer1',16,18)
INSERT INTO @LogTable VALUES ('WebServer1',17,16)
INSERT INTO @LogTable VALUES ('WebServer1',18,14)
INSERT INTO @LogTable VALUES ('WebServer1',19,12)
INSERT INTO @LogTable VALUES ('WebServer1',20,10)
INSERT INTO @LogTable VALUES ('WebServer1',21,8)
INSERT INTO @LogTable VALUES ('WebServer1',22,6)
INSERT INTO @LogTable VALUES ('WebServer1',23,4) 

SELECT WebServer, [Hour], NumberOfUsers FROM @LogTable

Next create a table, using hour as the column and the number of users as the data field

Creating the table

Now in right click on the report designer and select the “Report Properties” option, and then the “Code” tab. Copy the GetHeatmapColor function (NOT the SqlReportingServicesHeatMapGenerator class) and paste it into the window

Entering the VBA code into the report

Right click in the text box that you want to generate the heat map for and select “Text Box Properties” (or use the properties window)

Text Box Properties

Then choose the “Fill” tab and click the Expression button.

Entering the Expression

In the expression window enter the line below

=Code.GetHeatmapColor(Sum(Fields!NumberOfUsers.Value), Min(Fields!NumberOfUsers.Value, "DataSet1"), Max(Fields!NumberOfUsers.Value, "DataSet1"))

As Bob says his post “The argument ‘Dataset1′ defines the scope in which the min or max value is calculated, which must be a parent scope of the current scope.”

If you preview the report you should see the following

Jags Heat Map Report

Pimp Up Your Unit Test Assertions

Posted on | January 13, 2010 | No Comments

In this post I’m going to show you how you can write your unit test assertions to read more fluently and allow you to be more productive.

The Plain Jane Unit Test Assertion

[Test]
public void The_Plain_Jane_Assertion()
{
    const string firstString = "Hello World";
    const string secondString = "Hello World";

    const int smallNumber = 1;
    const int bigNumber = 500;

    // Are Equal
    Assert.AreEqual(firstString, secondString);

    // Greater Than
    Assert.Greater(bigNumber,smallNumber);

    // Less Than
    Assert.Less(smallNumber,bigNumber);
}

This is what most developers will start off using. No problem with the equals assertion it easy enough to read and use.

However when using the greater or less than assertions, it’s not clear if the first argument should be the lower or the higher value as shown in the screen shot below.

NUnit Assert Confusion

This distraction can easily stop your flow.

The More Fluent NUnit Test Assertion

[Test]
public void The_More_Fluent_Nunit_Assertion()
{
    const string firstString = "Hello World";
    const string secondString = "Hello World";

    const int smallNumber = 1;
    const int bigNumber = 500;

    // Are Equal
    Assert.That(firstString, Is.EqualTo(secondString));

    // Greater Than
    Assert.That(bigNumber, Is.GreaterThan(smallNumber));

    // Less Than
    Assert.That(smallNumber, Is.LessThan(bigNumber));
}

The unit test assertions read a lot more fluently, we no longer have to be concerned about the order of arguments.

If you don’t want to use another third party library, this is for you.

The Super Fluent NBehave Spec Assertion

[Test]
public void The_Super_Fluent_NBehave_Spec_Assertion()
{
    const string firstString = "Hello World";
    const string secondString = "Hello World";

    const int smallNumber = 1;
    const int bigNumber = 500;

    // Are Equal
    firstString.ShouldEqual(secondString);

    // Greater Than
    bigNumber.ShouldBeGreaterThan(smallNumber);

    // Less Than
    smallNumber.ShouldBeLessThan(bigNumber);
}

This example uses the NBehave Spec Framework which you can download from the NBehave site. In addition to being very easy to understand, the use of extension methods means there is a lot less noise.

Some developers will be concerned by losing the word ‘Assert’ in the line that does the assertion. If you arrange your tests using the Arrange, Act, Assert pattern this should not be a problem. See the example below.

[Test]
public void The_NBehave_Spec_Assertion_Using_Arrange_Act_Assert()
{
    // Arrange
    const int inputValue = 1;

    // Act
    var result = inputValue + 1;

    // Assert
    result.ShouldBeGreaterThan(inputValue);
}

Ever Thought About Changing How You Name Unit Tests?

Posted on | January 11, 2010 | No Comments

In the last couple of months I’ve seen a new convention of how developers are naming their unit test classes.

Traditionally the naming convention most developers use is to append the word ‘Tests’ to the class name as shown below.

public class UserValidation
{
}

[TestFixture]
public class UserValidationTests
{
}

There is absolutely nothing wrong with it, but this can lead to problems because a test class can become unwieldy and difficult to maintain either because it’s too long, testing a lot of different concerns or both.

In some cases it would make more sense to take different approach and adopt an alternative naming convention. Sticking with the example above instead of having tests for validating a user in one class, a new class could be created for each concern. So instead of

using System;
using NUnit.Framework;
using NBehave.Spec.NUnit;

namespace MyApplication.Validation
{
    [TestFixture]
    public class UserValidationTests
    {
        [Test]
        public void Should_Return_False_When_Username_Length_Is_To_Short()
        {
            // Arrange
            UserValidation userValidation = new UserValidation();

            // Act
            bool result = userValidation.IsUsernameValid(string.Empty);

            // Assert
            result.ShouldEqual(false);
        }

        [Test]
        public void Should_Return_False_When_Username_Length_Is_To_Long() { }

        [Test]
        public void Should_Return_False_When_Username_Contains_Invalid_Characters() { }

        [Test]
        public void Should_Return_True_When_Username_Is_Valid() { }

        [Test]
        public void Should_Return_False_When_Password_Length_Is_To_Short() { }

        [Test]
        public void Should_Return_False_When_Password_Length_Is_To_Long() { }

        [Test]
        public void Should_Return_False_When_Password_Is_Just_Numbers()
        {
            // Arrange
            UserValidation userValidation = new UserValidation();

            // Act
            bool result = userValidation.IsPasswordValid("123456");

            // Assert
            result.ShouldEqual(false);
        }

        [Test]
        public void Should_Return_False_When_Password_Is_Just_Alphabetical_Characters() { }

        [Test]
        public void Should_Return_False_When_Password_Contains_Invalid_Characters() { }

        [Test]
        public void Should_Return_True_When_Password_Is_Valid() { }
    }
}

we create two test classes

using System;
using NUnit.Framework;
using NBehave.Spec.NUnit;

namespace MyApplication.Validation
{
    [TestFixture]
    public class When_Validating_A_Users_Username
    {
        [Test]
        public void Should_Return_False_When_Username_Length_Is_To_Short()
        {
            // Arrange
            UserValidation userValidation = new UserValidation();

            // Act
            bool result = userValidation.IsUsernameValid(string.Empty);

            // Assert
            result.ShouldEqual(false);
        }

        [Test]
        public void Should_Return_False_When_Username_Length_Is_To_Long() { }

        [Test]
        public void Should_Return_False_When_Username_Contains_Invalid_Characters() { }

        [Test]
        public void Should_Return_True_When_Username_Is_Valid() { }
    }

    [TestFixture]
    public class When_Validating_A_Users_Password
    {
        [Test]
        public void Should_Return_False_When_Password_Length_Is_To_Short() { }

        [Test]
        public void Should_Return_False_When_Password_Length_Is_To_Long() { }

        [Test]
        public void Should_Return_False_When_Password_Is_Just_Numbers()
        {
            // Arrange
            UserValidation userValidation = new UserValidation();

            // Act
            bool result = userValidation.IsPasswordValid("123456");

            // Assert
            result.ShouldEqual(false);
        }

        [Test]
        public void Should_Return_False_When_Password_Is_Just_Alphabetical_Characters() { }

        [Test]
        public void Should_Return_False_When_Password_Contains_Invalid_Characters() { }

        [Test]
        public void Should_Return_True_When_Password_Is_Valid() { }
    }
}

I think this behavior driven development type naming convention will help focus on the problem you are solving and nothing more. This is very useful when doing test driven development.

When I first saw tests written like this my first thought was how am I going to find the all the tests for User Validation because they are no longer in a single class? If this is a problem for you think about using namespaces, folders or test attributes to organise your tests. Don’t forget if you use tools like ReSharper help you find where a class is being used very easily.

Remember this is about renaming your tests classes and not your methods. So even if you follow the MethodName_StateUnderTest_ExpectedBehavior pattern for test methods this could still work.

Congratulations Chris Alcock on 500 Morning Brew Posts

Posted on | December 17, 2009 | No Comments

My iGoogle page helps me keep up to date with the latest .Net news, podcasts and blogs with many RSS feeds I have subscribed to.

Unfortunately I don’t have the time to check out all of them and so it can be difficult to decide what is worth reading.

It’s lucky for me then Chris Alcock does a really good job of giving a summary for each of the blog posts he thinks are worth reading on his Morning Brew posts.

I reckon his Reflective Perspective blog must be the most underrated .Net blog.

Well done Chris, keep up the great work.

If you’re ever in Cambridge, I’ll buy you a beer.

I've contributed to The Morning Brew - Daily .NET News and Views

keep looking »