Test driven development is a development process in which you write your unit tests before you write your implementation. 

The process looks like this 

  1. Write a failing unit test. The test should be written in a way that describes what your code should be doing.
  2. Write just enough code to make the test pass. At this point it’s best not to worry about the quality of the code, just get a passing test.
  3. Refactor your code to improve readability and performance.

This is sometimes referred to as the Red/Green/Blue cycle

You then repeat this development cycle until the software is complete. One of the main reasons TDD is popular is because it removes the fear of change from projects, this is because the tests are always true and no matter what happens to your code, as long is the business logic is still sound. Refactoring also becomes significantly easier, any breaking change you make will be immediately apparent due to one or more tests failing. It’s true that you will be writing more code up front, however this will pay off in the long run as you will require much less time debugging issues, failed tests will identify issues immediately.

The Kata

Let’s dip our toes into TDD by using a Code Kata.

A Code Kata is an exercise in programming which helps developers hone their skills through practice and repetition. There are many code katas out there, I’m going to pick a simple one for this example. You can follow along in any language you chose, for this example I’ll be working in C#.

The steps in the kata can be found here : String Calculator Kata

String Calculator Kata – Step one

Create a simple String calculator with a method signature: int Add(string numbers)

  • The method can take up to two numbers, separated by commas, and will return their sum.
  • For example “” or “1” or “1,2” as inputs.
  • For an empty string it will return 0.

To start off I’ve created a new console project in Visual Studio, I’ve added a txt file that contains my Kata and I’ve also set up a unit test project using xUnit, removed the default unit test and created a reference to my StringCalculator project. I’ve also installed the FluentAssertions package via NuGet to help write my tests.

[Insert setup xunit project.gif]

Starting with the first requirements of the kata, I need something that will accept a string that accepts a single number or a comma separated pair of numbers, For example “” or “1” or “1,2”.

My first step is to create a class called CalculatorTests in the StringCalculator.Tests project. But we don’t have a Calculator class to test you might say? Well, welcome to TDD, we start from our tests! 

The next step I have taken is writing the skeleton of my first test:

A screenshot of a computer

Description automatically generated

If you’ve written unit tests before this shouldn’t look too scary, but nothing is going to run if we don’t set up our Calculator class, so I’ve created this class and filled out the logic so the test is no longer failing.

Text

Description automatically generated

And if I run the tests…wait a second!

A screenshot of a computer

Description automatically generated

I’ve got an IndexOutOfRangeException failing my tests, and this line is the culprit

Graphical user interface, text

Description automatically generated

Changing that [2] to [1] will resolve the failing test (this totally wasn’t an example of how writing tests first to catch unassuming errors is a great idea

A screenshot of a computer

Description automatically generated with medium confidence

So right now, we’re at the Pass stage of the TDD process, we’ve written the most basic code to satisfy the kata requirements, but are we proud of this code, is it as readable or as efficient as it could be? No.

We can use the split options to automatically remove any empty entries on the split level, rather than including one of the checks we have written:

Text

Description automatically generated

So there, we have refactored our code slightly, all tests are passing so we’ve completed a TDD cycle. Now we can move on to fulfilling the next kata criteria.

String Calculator Kata – Step two

  • Allow the Add method to handle an unknown amount of numbers.

Ok, so first step is to write a new test. Luckily, I can copy and tweak my old one. All I’ve done here is rename the test to reflect the outcome I’m looking to achieve and provided some different inline data to test we can handle different ranges of input.

Text

Description automatically generated

With that done, if I was to run the tests now, they would fail because we haven’t updated the Add() function to cover this requirement.

Okay, so thinking about the new requirement has reminded me of some linq features in C# I can use to optimise this code. Chaining .Select(int.Parse) to the end of our splitNumbers assignment gives us an IEnumerable of numbers that are not 0, we can then ditch all our old code and just return the sum of this list.

Text

Description automatically generated

And my new tests pass, nice!

A screenshot of a computer

Description automatically generated

I can’t think of any further way to refactor this so we can skip that stage and on to the next kata requirement

String Calculator Kata – Step three

Allow the Add method to handle new lines between numbers (instead of commas):

  • The following input is ok: “1n2,3” (will equal 6)
  • The following input is NOT ok: “1,n” (not need to prove it – just clarifying)

So next I’ve written a new test, again just copying a previous one and tweaking the name and the inline data we’re testing.

Text

Description automatically generated

And once again, this test will not pass until we update our Calculator class to handle this type of behaviour. It turns out this change is simple to implement because .Split() accepts an array of delimiting characters to split a string on, I just have to add the newline character into the array and my new test now passes!

A screenshot of a computer

Description automatically generated with medium confidence

And because of this change, we have an opportunity to refactor the Add() method, I think it would be more readable if I move the array of delimiter characters to a new line and just pass it in to Split() to keep things clean, especially if we have a requirement to add more characters to split on at a later date. 

Text

Description automatically generated

Ok, refactoring done, next Kata requirement!

String Calculator Kata – Step four

Support different delimiters:

  • To change a delimiter, the beginning of the string will contain a separate line that looks like this: “//[delimiter]n[numbers…]” for example “//;n1;2” should return three where the default delimiter is ‘;’.
  • The first line is optional. All existing scenarios should still be supported.

New test, you know the drill by now:

Text

Description automatically generated

To make things smoother I’ve converted my delimiters array into a list and commented the new code so you can see what’s going on. Note: we have to cast delimiters back to an array when passing it into .Split()

Text

Description automatically generated

I can’t think of any further way to refactor this so we can skip that stage and on to the next kata requirement.

String Calculator Kata – Step five

Calling Add with a negative number will throw an exception “negatives not allowed” – and the negative that was passed.

  • If there are multiple negatives, show all of them in the exception message.

I’ve copied an existing test but our inline data and method params need to be amended slightly since we are providing and returning a string of negative number/s, this is not a success scenario. And I’ve changed the Act part of the test to be an Action and amended the Assert part to check that a suitable exception has been thrown.

Text

Description automatically generated

Updating our calculator class is straightforward, we just need to check for any negative numbers (negative numbers are still ints in C#), add them to a list and throw and exception containing the negative numbers if we find any.

Text

Description automatically generated

Ok, so this code is passing the tests but that foreach loop is a bit messy, I’m pretty sure we can write that cleaner in linq like so, reducing the foreach loop down to a one-liner, nice and tidy.

Text

Description automatically generated

Nice, all tests are passing, and we even got some refactoring in there.

At this point I think I’ve shown how following the TDD process cycle can really inform you as a developer on how writing your methods in this way can make you consider what you really want from the code, as well as getting immediate feedback via failing tests if you make a mistake when updating the code in the future, freeing you to make change without fear of breaking untold dependencies and couplings.

There are 4 requirements left in the Kata, if you would like to have a crack at them yourself, please feel free to fork my repo here:  Code Repo It contains all the code I’ve written up to this point, beware the remaining 4 are a step up in difficulty!

I hope you have found this blog post useful!



Source link

Related Post

Leave a Comment