Test Driven Development in Python

TDD is a mindset

Test driven development is a way of designing as much as it is a way of developing.  I have been trying to use it on and off for a several years now without much success.  I think I understand the process, but not necessarily the mindset.  So, I am taking on a challenge in hopes of learning the mindset as well as the process.  The transition to TDD is going to take practice and I intend to get that practice using the Project Euler problems that I started on a couple of years ago.  One of the added benefits of using the Euler problems is that they are simple enough usually (or I should say, “So far”) that they can be solved using a single class or even a single method.  This makes writing tests for the design a little more direct and therefore simpler.

I have decided to use Python, for now.  Python is a simple language to use because it is interpreted rather than compiled.  I am also taking this opportunity to learn to use VIM a little better.  I have setup VIM as my python ide, and am pretty happy with it so far.  And when I am away from my main machine I can use my Koding virtual machine to work on a problem, but that is another post.  Plus I have always wanted to know more python, and so far I am really enjoying using it, it was super easy to get up and running with TDD.  Writing a unit test in python is very easy, as you will see.  So, despite the fact that I write C# all day everyday at work, I am trying to use an easier setup to get some practice in with Test Driven Development.

The Problem

I am currently on problem number 6 at Project Euler, which is title: Sum Square Difference.  The statement of the problem is this:

The sum of the squares of the first ten natural numbers is,

12 + 22 + … + 102 = 385

The square of the sum of the first ten natural numbers is,

(1 + 2 + … + 10)2 = 552 = 3025

Hence the difference between the sum of the squares of the first ten natural numbers and the square of the sum is 3025 − 385 = 2640.

Find the difference between the sum of the squares of the first one hundred natural numbers and the square of the sum.

This led me to do some research.  The past couple of problems I have tackled with more of a brute-force tack and so I decided that this time I would do some research first.  I knew there were some formulas that could help me with this one.  I basically needed a formula for the following:

  1. The sum of the squares for 1..n
  2. The square of the sums of 1..n

With formulas for these two tasks I could then simply diff the result for my answer.  I have sample values from the problem statement to use in my unit tests of the formulas.  Here are the formulas I will use in solving the problem, both were readily available through Google or Wikipedia searches.

Sum of Integers

Sum of Integers

Sum of Squares

Sum of Squares Identity

The Test Class (and the first test)

With test driven development, rather than writing some code for the problem first, of course I need to write a test.  So what test?  Well I look at the problem and see that I need to find the difference between the sum of the squares of a list of numbers and the square of the sum of those numbers.  Therefore I will need to be able to get those values.  My first test will be for a correct sum of squares value (the second formula above).

I know that I am supposed to dive right in and write a test for a method that does what I need.  This is where you actually do some designing as well.  I wrote the following test as the first code for this problem:

Test for a sum of squares method

Test for a sum of squares method

And here is the output for that test:

Output from run of first test.

Output from run of first test.

As you can see the test failed with an ‘ImportError:  No module named Problem6’.  That is because I need to add a module for Problem6, which is a new file named Problem6.py.  In order to maintain the strict tenets of test driven development I need to only to the minimum required to get past this error.  So I will add a new file/module named Problem6.py, and then re-run the test.  Here is the output from the next run:

Output from 2nd test run

Output from 2nd test run

Now we failed with an AttributeError: ‘module’ object has no attribute ‘Problem6Solution’ and this is because the new module we just added is empty and has no class.  So, I will add a class to the module and name it ‘Problem6Solution’ and a method named sumOfSquares that accepts an input number.  This should be enough to get through this error.  Here is the first look at the solution class:

Solution Class

Solution Class

Now we can run the test again and see what we get this time.  It should be an assertion error because we are not yet performing the formula calculation.  Here is the result:

Result from pass 3 of test 1

Result from pass 3 of test 1

Ah, there is my assertion error.  Now I am finally ready to add some code to execute the formula and hopefully pass the test.  The formula is simple but as I am a bit of a noobie with python I looked up the math.pow method to help me execute the power calls.  Here is the code for the sumOfSquares method complete:

Test1 - Passing!

Test1 – Passing!

Repeat for Remaining Tests

The rest of the process is a little smoother in that now we have our classes and files and beginnings completed.  We have a passing test and are under way!  The next test will be for another piece of our solution’s puzzle, the square of sums formula, where we sum 1..n and then square the result.  We have the formula for summing 1..n so it should be fairly simple.  Let us see what the test looks like:

Test 2 for a square of sums method

Test 2 for a square of sums method

Of course we will run the test without writing any new code to see it fail.  Then we will refactor until it passes.  I am seeing though, at this point that in writing a test first I am letting the desired output dictate the design of the class.  I am starting with what I need and only writing the minimum code in order to get it.  Resulting in a fairly concise bit of coding.  I am still only utilizing this at a very simple level, but I can see the benefits none the less.  What follows if the test result and the code written to make it pass:

Output from Test 2

Output from Test 2

Square of Sums method

Square of Sums method

And now our test 2 passes.

Test 2 - Passing!

Test 2 – Passing!

For the last test, where we test a solve method that takes the difference of our two sums, I will show the resulting classes in their entirety.  You will notice there will now be a third test and a third method in the solution class, called ‘solve’.

The complete test class

The complete test class

Complete solution class

Complete solution class

Summary

I have added a main method at the end of the solution class that actually shows the answer and the elapsed time to calculate it.  That, in my mind, makes this a complete solution that does provide the output desired.  And, thanks to Test Driven Development, without anything extra.  Of course I could further refactor the formula methods to shorten them, specifically using the sum() method rather than the += operator.  However, I have left the code the way it is because I feel it is more readable this way.  And in my book, readability counts for something.

Lastly here is the output, both the passing tests and the printed answer!

All Tests Passing!

All Tests Passing!

Results!

Results!

Advertisements

One Comment on “Test Driven Development in Python”

  1. KyEnglishman says:

    In finite systems, where most code design and algorithmic development is mechanical, you are right on the money – and developers would be much contented to have such a system that could automatically evaluate and debug libraries and the like. This especially works for scripting languages, controlled flow languages and embedded systems – perhaps even services and the like.

    My only point of concern is that development outside this realm still leaves something be desired – in other words, development that is not so finite in nature, where inputs, parameters and other reference items are subject to user control. To cover all possibilities is almost non-realistic, and you still have to have a dedicated source (or resource) that exercises these types of things to build agnostic tests and (hopefully) achieve a level of confidence in the development.

    Your article though, is really good – and it goes to show you do not have to implement carefully laid logic as such in high-level languaes alone. I’ve seen some pretty sharp stuff come out of Python lately – especially when used with library extensions and the like – that makes its simplicity just as full powered as the bigger boy development environments. Congrats!


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