How I Discovered A Love For Test Driven Development... Part 2
27 May 2013 - Nic Ho Chee
In a previous post we covered an introduction to Test Driven Development. In brief it is a process by which a programmer can create simple, automated tests which capture application logic and allow for sections of the code to be continually validated. You can have a read at the link above...
This post aims to give a boot-strap introduction to NUnit and shows how some simple principles could be used to ensure decent coverage for a chosen problem.
The power industry uses Electricity Forward Agreements (EFA) to trade electricity amongst the various companies that produce, consume or speculate in energy in the UK. Units traded tend to be some fraction or multiple of 1 Megawatt Hour (MWh) and physical trades will have a delivery component which will need to take account of the EFA calendar to calculate the total amounts destined for delivery.
The EFA calendar in brief breaks down as follows:
- An EFA delivery day is 24 hours long, starting at 11pm and ending at 11pm the following day.
- A day is split into six blocks numbered 1 through to 6, each of which is four hours long.
- An EFA week contains seven days as normal and starts at 11pm on a Sunday.
- An EFA month can be either four or five weeks depending on when it falls in the year. The first three months are split into 4/4/5 weeks so January and February are four weeks long while March is five weeks long. Some of the days in the standard calendar month of January for example may fall in the EFA February month.
- An EFA quarter is 13 weeks long, containing two four week EFA months and one five week EFA month.
- An EFA year starts at 11pm on the Sunday of the week containing the first Thursday of the year and contains weeks numbered 1 to 52.
Some method we have yet to create will generate the volume of energy over some period of time. The granularity can be less than a block and may be in the range one to fifteen minutes in some cases. How do we ensure that each delivery minute is attributed to the correct EFA week so that we can calculate the total energy volume per EFA week for a single year?
Breaking The Problem Down
Before we start thinking about possible solutions to the question of calculating energy delivery volumes we should think about how we can test any results obtained. As a first step we know that for a given unit of energy, we will discover in which EFA week the energy is to be delivered. For this we'll need to find which EFA week contains any given instantaneous timestamp which will probably be stored in a C# DateTime structure. We have just uncovered something we can create a unit test for!
If the flow of energy is measured each minute there will be at least 525600 data points generated each year and to create a useful test for the complete set of data will be impossibly time-consuming and error-prone for your average (or even better than average) programmer. Exhaustive testing of most systems is impossible given problem complexity so some simple choices should be made to try and give the most coverage for the smallest coding cost.
Since we're interested in working out which week a given minute might fall in and we know there are only 52 weeks in a year, a lot of the data is effectively equivalent. We want to partition the data points to test into sets containing essentially the same elements. This is a technique known as Equivalence Partitioning. Given the information we know so far we only need to separate the data into 52 equivalent buckets, one for each week in the year.
We have reduced 500k+ data points into 52 equivalent sets, so we now need to work out which of these we're going to test. A decent heuristic is that the most likely source of error will be at the intersection between the sets, so we want to test a data point either side of that position. This is a selection process known as Boundary Value Analysis. which would yield a total of 104 data points to test :). The problem states that we're only working with a single year, so we shouldn't include any un-necessary information, which in this case would include the last point from the previous year and the first point from the following year. Changes across EFA year boundaries could be rolled into another test once the specification changes.
In the past I have added an extra random datapoint for each equivalent set to satisfy my curiosity. There are now 156 data points for a programmer to validate through some other mechanism and add into an automated test.
Hello NUnit My Old Friend...
To try out this example you need the following tools:
- A C# compiler. You can use Mono but the example uses Visual Studio Express which can be downloaded for free here.
- A unit testing framework. The example below uses the NUnit framework which is available here.
- Download and install NUnit using the MSI package.
- Start Visual Studio and create a new C# project which will generate a C# Class Library.
- Add the nunit.framework.dll assembly to the project by right clicking the solution in the Solution Explorer and selecting the "Add Reference" menu item. The file lives under <NUnit X.X.X>/bin/framework/nunit.framework.dll.
- Create the first failing test :). It doesn't have to capture the testing logic completely yet, we just need a framework we can start to work with... I've included an example below:
- A brief explanation of the code shown above:
- The NUnit framework assembly is included through the using NUnit.Framework statement. This will allow you to access the attributes which mark your classes, methods etc for use by the various NUnit test runners.
- The TestFixture attribute informs the compiler that the class will contain zero or more tests as well as optional methods to put the system into a known state before each test is run and clean up after each test.
- The SetUp attribute marks a method which will be run before each test in the fixture and prepare the system for running each test.
- The TearDown attribute marks a method which will be run after each test in the fixture and can be used to return the system to a known clean state.
- Tests are marked by the Test attribute. In the code shown below there is a single failing test defined by the DateTimesIn2013HaveTheCorrectEfaWeek method.
- Launch the NUnit.exe test runner and load the DLL created by the compiler through File > "Open Project". Run the unit test and make sure that it fails. It is important that you prove that you have a failing test to ensure that your expected changes made the test pass rather than some code error which inadvertently created a passing condition. You should see something which looks very similar to the screenshot shown below:
- We can now create the set of EFA Week data points we outlined previously. In the code shown below we're populating a set of DateTime objects which map the boundaries for EFA weeks in 2013 and check them against the output of our EfaDateTime stub class allowing us to map a delivery timestamp to a given EFA period.
- The example code above shows a single test with a single assert giving some sensible output which should allow a future programmer to track down the source of error quickly should any regression issues creep into the code. Ideally there should be a single assert per test to increase the amount of information that is returned with each run. If there is more than one assert per test method the engineer may have to fix the code which powers each assert and re-run the tests to progressively uncover broken code, where possible this should be avoided.
- As a final check before populating the stub the test runner should re-run the unit test to ensure that it is still failing. As the run shows below the code is failing as expected with some helpful error output.
The programmer is now in a good place to be able to fill out the stub method and return an EFA week from a DateTime in the 2013 EFA year.
Dependency injection and what you can do with it...