#tdd #development

Getting My Head Round TDD

In the latter part of last year I decided I wanted to upskill. Checking out the jobsites I determined a general trend towards Test Driven Development, or TDD, and thought that might be a good place to start.


Now this was a bit of a leap for me. My then team were of the mind-set that we should hack out vast amounts of code and let QA pick up the issues. Which on one release resulted in me working solidly on regression bugs for eight weeks. Eight weeks!!

I had been interested in SOLID principles for some time so at least I had a good grasp of the facets of TDD even if I was yet to put them into practice.

But with a completely test free solution, I had barely written a unit test let alone dived into TDD.

Where to begin?

After researching the key benefits, such as safer refactoring, greater focus and fewer bugs I was determined to push ahead.

So, my first port of call was to trawl through some tutorials. These talked about the principles of TDD, which I was already familiar with, but didn’t really get into the ‘meat’ of my issue – how does one actually go about it?

Next, I dived into some videos. Tests were written at top speed, with builds whizzing past and little red circles transforming, as if by magic, into green ticks.

I was still at a loss as to where to begin. So I decided I just had to jump in and get some code down.

I then came grinding to a halt…. What could I write that was testable? Being mainly a web developer churning through CRUD it didn’t feel like a true test to check if my “Controller returned a View”… I needed something a bit… well a bit more ‘code-y’.


Enter The Terminator!

image showing the Terminator

Being a massive fan of the Terminator films I decided that a simple program to determine whether a Terminator should investigate a potential threat or not seemed like a good starting point!

Now, my project, TDD and the Terminator, did veer off course a little…. I decided to use it to also delve into some of the SOLID principles that I wasn’t so clear on, such as ‘Open/Close Principle’ – just how does that work in practice and not solely in the theoretical?

I managed to write some tests, a few of them TDD, but not as many I would have liked. However, the little demo helped to cement my understanding of the practical application of SOLID and how it can help with testing.

It can be found on my github repository (there’s more I want to do with this in time!)


The truth is, until you are actually working on a solution that is test-driven it is really hard to instigate TDD for training purposes.
I did, however, manage to write a little bit of code which I feel shows TDD in action, especially the Red/Green/Refactor process.

image showing the red green testing flow

What is the Red/Green/Refactor process, I hear you say?

Well, this is the cool part! Well I think so, at least!

The idea is to write just enough code to make a test pass. Take the example below, a simple extension to IEnumerable to return a paged result:

public static class PagingHelperExtension
{
    public static IEnumerable<T> ToPaged<T>(this IEnumerable<T> items, int page, int pageSize)
    {
        throw new NotImplementedException();
    }
}


Here is the first test for it - note I am using NUnit for my testing framework.

[Test]
public void GivenCollectionIsLessThanOrEqualToPageSize_Should_ReturnCompleteCollection()
{
    var list = new List<int>{1, 2, 3, 4, 5, 6, 7, 8};
    list.ToPaged(3, 2)ShouldBeEquivalentTo(list);
}


Now, you may want to just dive in and write the whole extension in one go… but Steady Eddy!! Remember that this is TDD and you have to get into the flow of it! We just have to get this test to pass, nothing more. Let’s just return the list.

public static class PagingHelperExtension
{
    public static IEnumerable<T> ToPaged<T>(this IEnumerable<T> items, int page, int pageSize)
     {
        return items;
     }
}
   


That’s it! We have our first passing/green test! Whoop, whoop!

So our next test will cover the page size aspect of the function.

[Test]
public void GivenCollectionIsGreaterThanPageSize_Should_ReturnCollectionOfSameLengthAsPageSize()
{
   var list = new List<int>{1, 2, 3, 4, 5, 6, 7, 8};
   list.ToPaged(1, 4).Count().ShouldBeEquivalentTo(4);
}


So we can use .Take() to achieve this.


public void public static class PagingHelperExtension
{
    public static IEnumerable<T> ToPaged<T>(this IEnumerable<T> items, int page, int pageSize)
    {
      return items.Take(pageSize);
    }
}
    
    ```
    </br
    That’ll be another green light, we are zooming!

Let's add a few more tests and finish the example.
```csharp
[Test]
public void GivenCollectionIsGreaterThanPageSize_Should_ReturnCollectionOfSameLengthAsPageSize()
{
   var list = new List<int>{1, 2, 3, 4, 5, 6, 7, 8};
   var list = new List<int>{ 3, 4};
   
   list.ToPaged(2,2).ShouldBeEquivalentTo(expected);
   list.ToPaged(2, 2).Count().ShouldBeEquivalentTo(expected.Count);
}

[Test]
public void GivenPageEmptyList_Should_ReturnEmptyList()
{
   var emptyList = new List<int>();
   emptyList.ToPaged(1, 10).ShouldBeEquivalentTo(emptyList);
}

[Test]
public void GivenInvalidPageNumber_Should_DefaultToPageOne()
{
    var list = new List<int>{1, 2, 3, 4, 5, 6, 7, 8};
    var expected = new List<int> { 1, 2, 3, 4, 5 };

    list.ToPaged(0, 5).ShouldBeEquivalentTo(expected);
    list.ToPaged(-1, 5).ShouldBeEquivalentTo(expected);
}


And the final function looks like this:

public void public static class PagingHelperExtension
{
    public static IEnumerable<T> ToPaged<T>(this IEnumerable<T> items, int page, int pageSize)
    {
       return items.Skip((page - 1) * pageSize).Take(pageSize);
    }
}


I’m sure there are more tests to be written or different ways to achieve the same functionality, but this little snip is just a demonstration of one way to start TDD.


To conclude, I have now been working in a TDD environment since the beginning of 2018.

I do like it, even if sometimes I do spend more time writing tests than actual code but I’m sure that I’ll speed up with practice!

Give it a go, persevere. I think it’s pretty powerful.