At this years Open Force Europe conference, I will be doing a presentation on Testable Modules. In preparation for that talk, I have been researching and developing examples. In this series of blogs I will be building the concepts for creating Testable Modules. My goal here is to show you how to adapt your Module Development process to make your modules more testable.
Phil Beadle has developed an excellent project template for Test-Driven Module Devlopment, and if you are interested in this topic you should review his posts and download his template. I propose to take a slightly different tack, and show you how (and why) each decision in the design process is made.
I would like to emphasise that I am new to this game - I will be writing these blogs as I learn and develop the ideas - so if there are any purists out there reading this - please accept my apologies for any egregious errors, or over-simplifications.
In this first post of the series (which is cross-posted from my personal Blog), I provide some background information to get us started.
Creatting Testable Modules - Part 1, Introduction
In a traditional ASP.NET Application, a page (WebForm) contains controls (WebControls and UserControls) that display application domain data. A user can modify the data and submit the changes, via Postbacks. The page retrieves the domain data, handles user events, alters other controls on the page in response to the events, and submits the changed domain data to the Business Layer.
Including the code that performs these functions in the Web page makes the class complex, difficult to maintain, and hard to test. In addition, it is difficult to share code between Web pages that require the same behavior.
Recently there has been much more emphasis on the use of automated Unit tests in the development cycle. The benefit of automating Unit Tests, which can then be run whenever a change is made to the code is that it has the potential to free the QA resources to focus on the Usability of an application and on the exceptions (edge cases), as the application has been well tested before it gets to the QA team.
Of course, this all depends on how well the tests have been written and how much of the Application the tests cover (code coverage).
Unit Tests
A unit is the smallest testable part of an application. Typically, the smallest unit is a method, which may belong to a base/super class, abstract class or derived/child class.
Ideally, each unit test is independent from the others, and double objects like stubs, mock or fake objects as well as test harnesses can be used to assist testing a module in isolation.
The goal of unit testing is to isolate each section of the program and show that the individual sections are correct. A unit test provides a strict, written contract that the piece of code must satisfy. As a result, it affords several benefits, as unit tests find problems early in the development cycle.
Test Driven Development
Test-Driven Development is a style of software development that takes this use of testing to the extreme. In Test-Driven Development (TDD) the Unit Test is written first, and then the minimum amount of code is written to get the test to pass. Most testing frameworks use the red light/green light approach – red light, the test fails – green light, the test passes. The complete cycle of Test Driven Development is as follows (from Test-Driven Development, By Example – Kent Beck)
- Write a test
- Run all tests – and see the new test fail
- Make a little change – to make the test pass
- Run all tests and see them all succeed
- Refactor to remove duplication
- Repeat
The important steps are (3) and (5). The initial coding to make the test pass should be as small as possible.
For instance if you are creating a math function to multiply two numbers together and your test invloves calling the function with the two numbers 2 and 5, and checking that the answer is 10, a TDD purist would say that the initial implementation of the function should just return the literal constant integer 10, as this is the simplest code that satisfies the test.
It is in step (5) when the duplication is removed that causes the code to be refactored to return param1 * param2.
Loosely Coupled Systems
In order to test one component, independently from another, the components should be loosely coupled. This is not always the case with software. Often a business layer class will have a dependency on the database. In this scenario, a method in the business layer cannot be executed without affecting the database. The data layer can probably be independently unit tested, but the business layer is said to be tightly couple to the data layer, as it cannot exist in isolation.
Testable DotNetNuke Modules
The conventional methodology for building DotNetNuke modules does not lend itself to support Unit Testing (or by extension Test-Driven Development) for a number of reasons.
- While the Data Layer is quite loosely coupled from the Business Layer (through the DataProvider model) the providers are configured through the web.config file, and there is no way (prior to version 5.0) to independently create a MockDataProvider to enable us to test the Controller classes in isolation from the database.
- Web Forms (and User Controls) do not provide a way to independently Unit Test the Presentation Layer – there are browser-automation frameworks like Watin and WebAii, which can automate user interaction with the Page – but these are not Unit Tests.
In this series of blog posts I will discus ways we can modify our normal module development process to create Testable Modules. While I will discus Test-Driven Development, the real goal in this series of blogs is to build testable modules, regardless of the development process you decide to use.