Wednesday, July 25, 2012

Tests with a Twist

Test Driven Development (TDD) plays a big part in our modern day development life-cycle as it allows us to write stabler code more efficiently. The idea behind it is to create an automated testing environment for the optimal continuous integration process.

"Test-driven development (TDD) is a software development process that relies on the repetition of a very short development cycle: first the developer writes a failing automated test case that defines a desired improvement or new function, then produces code to pass that test and finally refactors the new code to acceptable standards. Kent Beck, who is credited with having developed or 'rediscovered' the technique, stated in 2003 that TDD encourages simple designs and inspires confidence." - Beck, K. Test-Driven Development by Example

The concept of  'Test-first then Code' keeps us developing code in-line with the required use-case, having the code solve the test and the test (when passed)  guarantees a rock solid solution for it.

Test-Driven Development Cycle

  1. Write a test for a specific unit of work
  2. Run test to see if it fails (if it's the first iteration it has to fail as there should be no implementation)
  3. Implement / re-factor code 
  4. Repeat from nr. 2

Okay, that covers rock-solid code. What about data validity?

Writing the right code matters. When dealing with infrastructure-based code; TDD is a big plus, but having data-driven functions in the mix, might make it a bit more difficult to do properly.

In a case where you have to, for instance; read specific data, do complex calculations and provide a accurate result from it, we require "dummy data" based on a mock-model in our tests. This requires us to make a [hard-coded] cast-in-stone mock-up of the dependent data-source in order for our test to work properly. We don't want the data to keep on changing, so that's why we need static content.

I've blogged before on a pattern that allows you to do this kind of mocking-up.

Cool, but what about big chunks of inter-dependant data?

Having been there and done that (waiting for my t-shirt), I realised doing mock-ups of inter-dependant data can become cumbersome, specially when working with different scenario-testing.

I came up with a way to help both the client and myself in this situation, which enables the compilation of proper test-packs.

Case study

My client Poenie requires a system to calculate accurate cash-flows on a inter-dependant hierarchy model. Given different scenarios, we need to make sure that the system caters for all needed business requirements.

Obviously it's a no-brainer that captain TDD is our hero here, but implementing it wrong can cost a lot of time (and money). We needed a way for business to be involved with the testing process as well as the compilation of test packs, instead of me keeping track of the hard-coded mock model.

Our Solution

Leveraging the features of Microsoft Excel, XSD, XML & .NET it enables us to do exactly what we want. By creating an Excel template that uses a pre-defined XSD schema mapped on a sheet, we allow the client (or business analyst) to compile the inputs and the expected output in a structured and simple fashion.
They can document the workbook including additional notes; then export the file as a XML. We include the latter in our Test project and have a process that serialises the XML as a strongly typed TestPack class before running the test.

The actual test runs through the inputs, calls the applicable calculation process and asserting it against the expected result.

1. Create XSD


2. Create Excel template with a XML source. From the Developer tab, select 'Source' then click 'XML Maps'

Add the XSD from disk to the workbook by clicking 'Add...'. You will notice that you now have access to the fields:

You can drag-n-drop the fields on the sheet where you want it.

3. Use the template. Keep in mind that only the field value is mapped so you can still use formatting on the cells as per normal:

4. Export spreadsheet as XML


5. Import XML into test project
6. Use a component like LINQ-to-XSD to serialise XML into C# class
    public class TestPack
        public string Name { get; set; }
        public DateTime Date { get; set; }

        public ICollection Items { get; set; }
        public ICollection Results { get; set; }

    public class Item
        public string Code { get; set; }
        public decimal Amount { get; set; }

    public class Result
        public string Code { get; set; }
        public decimal Amount { get; set; }

7. Implement test by iterating through items asserting the actual against the expected result
        public void TestCalculation()
            var path = "...";
            var testpack = XSD.Load(path);

            var actualResult = CalculateValues(testpack.Items);

            var testItems = from a in actualResult
                            join e in testpack.Results on a.Code equals e.Code
                            select new {
                                ActualCode = a.Code,
                                ExpectedCode = e.Code,
                                ActualAmount = a.Amount,
                                ExpectedAmount = e.Amount

            foreach (var item in testItems)
                Assert.AreEqual(item.ExpectedCode, item.ActualCode);
                Assert.AreEqual(item.ExpectedAmount, item.ActualAmount);

Thats all she wrote!

This approach helped us doing extensive data-validity tests using proper TDD methodologies and allowed the flexibility to have & maintain any kind of test pack within our solution and not re-doing our mock-data.

I hope that someone will find this helpful as well.

Till next time


No comments:

Post a Comment