The First Test

We are at the point of writing our first test, but first lets review the whole test first pattern, that is the hopefully well known

Red
Green
Refactor

although it seams to be well known I think there has grown up a lot of myth and folk law around the process that gets in the way of actually carrying out what is on the surface a simple process.  But a bit like chess this simplicity hides a complex thought process that has to be practiced and when performed well leads to code that is well designed, extensible and easy to maintain. 

Lets take this one stage at a time and work through the first test and see how the process translates into code.

Red
Within this phase we write our test, as will be seen we will also be writing some production code, in order to keep what we create compiling and syntaxially correct, we will not worry about duplication or design at this point, our aim is to write a purposefully failing test.

Our first test is about the creation of a basket, as discussed in the previous post, our first task is to create a test class in the  Checkout basket specifications project this class will inherit from the BddBase class.  All the following code was created in the “createbasket” branch of the repository.

    public class When_calling_the_basket_api_without_an_id : BddBase
{
protected override void Given()
{

}

protected override void When()
{

}
}

Our code at this point still compiles. 
 
The “Given” method is where we will setup our system to run the specific set of tests, in the “When” method we will call the actual public method under test, ideally this method should be a single line where we get a result from our call that our test methods can assert on, but as we will see this is not always the case. 
 
Where we start writing code now depends on the situation, if we have classes and methods that we can call already then we could start with creating the setup and calling the method.  But in our case we have nothing, so we must start with the test method.
 
Naming our test can be complex, I always suggest that the best idea is to get something down and change it as you start to write the actual code, the name of a test like everything else is refactorable, but in order to get to the refactor stage we need something in code.  In our case we are saying that the call will result in a new empty basket, so lets say that.
 
        [Test]
public void Then_a_new_empty_basket_is_returned()
{

}

Notice our code still compiles, I am not sure how we are going to test for newness of our basket, but checking for empty should be easy, if our basket has a collection of items, then we can check for there being no items in the basket.   Lets code that, we will need a field variable to hold our basket as this will be returned inside the “When” method,
 
        [Test]
public void Then_a_new_empty_basket_is_returned()
{
_basket
}

Now our code will not compile, because we do not have a declaration for the “_basket” field, lets add that.

        private Basket _basket;

adding this declaration will require the creation of a “Basket” class, in order that we continue progressing at this point I would suggest simply creating the class in the same file as we are currently working in.

    internal class Basket
{
}

I created the class using a Resharper shortcut, and the tooling has created it internal, but at this point I don’t care, we want to make progress so lets leave it for the time being.  Back to our test we can now assume our field variable contains a basket, so the next bit is to get the items in the basket.
 
        [Test]
public void Then_a_new_empty_basket_is_returned()
{
_basket.Items
}
 
Our code won’t compile because “Items” is not defined on the “Basket” class so lets add that now
 
    internal class Basket
{
public IList<Object> Items { get; set; }
}

Back to our test and finally we can see if there are any items in the basket, and assert on the result of the check.
 
        [Test]
public void Then_a_new_empty_basket_is_returned()
{
_basket.Items.Any().ShouldBe(false);
}
 
And our code is back to compiling again. 
 
But the test will fail because _basket is not set anywhere!  so lets fill out the given and when steps.  A quick lookup at the Nancy documentation shows that we can create a bootstrapper that is handed to a special test browser, that we can use to make our API call on, this is almost a copy from the Nancy documentation.
 
        protected override void Given()
{
var bootstrapper = new DefaultNancyBootstrapper();
_browser = new Browser(bootstrapper);
}

protected override void When()
{
var response = _browser.Get("/basket");
}

Now we have a response, which we need to turn back into our basket so our test will work.  As it turns out the Nancy Response object has a method for converting JSON back into an Object, so we use that to get our basket from the JSON.
 
        protected override void When()
{
var response = _browser.Get("/basket");

_basket = response.Body.DeserializeJson<Basket>();
}

We are still compiling but our test fails! Why?
 
At each stage we are writing our code we always need to be aware of why the test is failing, as this can help guide us on what code we need to write next, and it ensures that we actually understand the code we are writing!  In this case the response is getting a 404 not found error.  Which is expected, we have not written any code to handle the “Get Basket” call
 
This completes the red phase of our process, notice how we always tried to keep the code compiling even during the writing of the test, we only created just enough to get the test to fail even when failing was simply not compiling.  We are now ready to make the test pass.  
 
Our test file looks like this.
 
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Nancy;
using Nancy.Testing;
using NUnit.Framework;
using Shouldly;

namespace CheckoutBasket.Specifications
{
public class When_calling_the_basket_api_without_an_id : BddBase
{
private Basket _basket;
private Browser _browser;

protected override void Given()
{
var bootstrapper = new DefaultNancyBootstrapper();
_browser = new Browser(bootstrapper);
}

protected override void When()
{
var response = _browser.Get("/basket");

_basket = response.Body.DeserializeJson<Basket>();
}

[Test]
public void Then_a_new_empty_basket_is_returned()
{
_basket.Items.Any().ShouldBe(false);
}
}

internal class Basket
{
public IList<Object> Items { get; set; }
}
}

 
Green 
It is during this phase that a lot of us being to make our mistakes, we start to worry about design, and clean code and all the rest of the very good practices that we will be worrying about in the future, but to worry about them now, and attempt to implement them is a mistake.
 
Our task at this point is to make the test pass as quickly as possible. 
 
One of the very good practices, that can help to keep us moving fowrward is to say that if you have not made the test pass within one pomodoro (25 minutes) then you should back out of your code changes remove the test and write a test that does a smaller chunk of work.   I would add to this, that if you haven’t changed the error message within 5 minutes of starting then you should back out, because what you are attempting to do is too big and should be broken down into smaller tasks.
 
Do not be afraid to back out of a test and rethink the problem, remember our tests are there to support the design and implementation of our code, so if we have bitten off more than we can comfortably chew then its always best to back out, redesign the test and plunge in again.   The future code will always be better, because your understanding of the problem and its domain is going to be enhanced as you explore we each new test.
 

I cannot over emphasise this enough, we need to get the test passing as quickly as possible,

At this point in the process we are going to break every rule of coding, cutting and pasting code, copying from the internet, stealing from other projects do what ever you have to, make the test pass, and do it quickly. 

Ward Cunningham put is best when he said do the simplest thing that can possibly work, simplicity is the shortest path to a solution, notice he didn’t say best, or well engineered, its the shortest which at this point is what we want, we need our code to work, for the test to be green and for us to be able to move on as quickly as possible. You have permission to do your worst break the rules, and make the test pass.

For us we need a handler for the basket get method, so lets quickly put this together, add a new class to the “CheckoutBasket.API” project.

Nancy uses the constructor of the class to setup routing for a method.

using Nancy;

namespace CheckoutBasket.API
{
public class BasketHander : NancyModule
{
public BasketHander()
{
Get["/basket"] = _ =>
{
return null;
};
}
}
}
 
Our code compiles, but the test still fails, but the message has changed to object not set to an instance of an object.
 
Because we are returning null from our method! And therefore the basket in our test is set to null, the error is caused by trying to access the items collection on the null basket. 
 
So we need to move the basket class we created earlier into the “CheckoutBasket.API” project (that’s a simple f6 in Resharper) make it public so our code compiles, Then return a new basket with a new collection of items from the basket handler as JSON.
 
using System.Collections.Generic;
using Nancy;

namespace CheckoutBasket.API
{
public class BasketHander : NancyModule
{
public BasketHander()
{
Get["/basket"] = _ =>
{
return Response.AsJson(new Basket() {Items = new List<object>()});
};
}
}
}

And our test now passes, well done, commit to save all of our changes and its onto the one stage that is the most important and the most neglected.
 
Refactor
 
When we wrote the code to make the test pass we ignored all the rules for clean code and good design, because we needed to get to green quickly.  Developers almost naturally try to design when they code at they are writing it, which means that the refactor stage is often forgotten or is delayed until some point later when there is “more” code to look at. 
 
What I want to show now is that we need to think about it after each passing green, even if there is only a singe line of code!
 
So lets take a look at our code starting with the test we have written.  Looks fairly reasonable, and in truth it is not bad, but we can improve it. 
 
The test states in its title that “Then a new empty basket is returned”, well we know its new because the handler creates a new basket, but the test doesn’t know that, but it does check for the basket being empty.  I think we can rename this test a bit to reflect what the code is actually saying, the code ensures the basket is empty, so lets rename it to “Then an empty basket is returned”.
 
The actual code in the test is a bit more complex, we are actually reaching into the object grabbing its items collection and then calling an extension method to check to see if it is empty, not exactly intuitive.
 
How about having an IsEmpty property on the basket this would stop us from reaching into the object and will tidy up our tests.
 
In the basket class create a read only property IsEmpty and copy the code from our test into it so that it returns true if “Any()” returns false;
 
    public class Basket
{
public IList<object> Items { get; set; }

public bool IsEmpty { get { return ! Items.Any(); } }
}
 
And change the test to call our new property
 
        [Test]
public void Then_an_empty_basket_is_returned()
{
_basket.IsEmpty.ShouldBe(true);
}

 

Now looking at the handler we are returning a new basket which is correct but should be also be doing the initialization of the items collection in the handler as well, lets move it to the constructor of the basket, stopping the handler knowing about the internals of the basket.

    public class BasketHander : NancyModule
{
public BasketHander()
{
Get["/basket"] = _ =>
{
return Response.AsJson(new Basket());
};
}
}

We can now also make the items property private as no one else accesses it.

    public class Basket
{
public Basket()
{
Items = new List<object>();
}

private IList<object> Items { get; set; }

public bool IsEmpty { get { return ! Items.Any(); } }
}

Actually we can make the items list a field, because no one needs access to it currently, so lets do that as it simplifies our code even more.
 
    public class Basket
{
private IList<object> _items;

public Basket()
{
_items = new List<object>();
}

public bool IsEmpty { get { return ! _items.Any(); } }
}

The last bit of refactoring I want to do is within the solution it self moving the handler and basket classes to their own folders, I want to start to add a bit of structure to the project to ease navigation in the future.
 

create basket first test

With that I think we are just about done, the end of the initial test first development phase, notice how we took time over the refactoring,.

We should have taken as much time over the naming of our tests as this helps with designing the API, the only phase we rushed to get through was the getting to green, where we broke all the rules and “Just made it work”.

Once green we went back and applied all the laws of good coding practice, refactoring the code to make it maintainable and easy to read.

All through the process we aimed to keep the code compiling, and the tests running, even while building the very first test, then once failing we got to green as quickly as possible.  again keeping the code compiling, only at this last stage do we apply the rules of software design, and because our tests are on the outside looking in, we are able to refactor the internals of our application without breaking tests.  Next up will be the id and some thoughts on storage.

Advertisements

About Duncan Butler

Trying to be a very agile software developer, working in C# with Specflow, Nunit and Machine Specifications, and in the evening having fun with Ruby and Rails
This entry was posted in Programming and tagged , . Bookmark the permalink.

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