[ad_1]
Test driven development is a development process in which you write your unit tests before you write your implementation.
The process looks like this
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.
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
Create a simple String calculator with a method signature: int Add(string numbers)
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:
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.
And if I run the tests…wait a second!
I’ve got an IndexOutOfRangeException failing my tests, and this line is the culprit
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)
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:
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.
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.
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.
And my new tests pass, nice!
I can’t think of any further way to refactor this so we can skip that stage and on to the next kata requirement
Allow the Add method to handle new lines between numbers (instead of commas):
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.
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!
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.
Ok, refactoring done, next Kata requirement!
Support different delimiters:
New test, you know the drill by now:
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()
I can’t think of any further way to refactor this so we can skip that stage and on to the next kata requirement.
Calling Add with a negative number will throw an exception “negatives not allowed” – and the negative that was passed.
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.
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.
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.
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!
[ad_2]
Source link