Aug
14
Posted by:
Charles Nurse
8/14/2008
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.
3 comment(s) so far...
Re: Creating Testable Modules - Introduction
Charles,
Excellent introduction. This will be an exciting series to follow. Thanks for sharing the learning process with the community.
Rob Conery did a similar thing on ASP.NET MVC where he started using TDD and had to have the flame shields on!
I am going down a similar path and find resources like the polymorphicpodcast series on the presenter pattern very helpful.
Jim
By jbonnie on
8/15/2008
|
Re: Creating Testable Modules - Introduction
Yeah - I hear ya Jim. I have been following Rob's video series, and this kindof influenced my approach too - although I am not sure I have the time to make Videos.
When one learns in public - one makes mistakes - and risks being attacked by the purists.
By cnurse on
8/15/2008
|
Re: Creating Testable Modules - Introduction
I think this is a great direction for DNN. I'm not a TDD fanatic, but I sure appreciate the fact that this methodology produces code which is properly layered. One of the things I would love to see in the DNN infrastructure is better use of interfaces as contracts between the layers. I would also like to see more examples of modules developed with a service layer sitting above the BLL layer. As I've worked recently with the code from multiple projects, including the Blog project, I've seen a lot of code that looks like this:
'Code to check permissions ... myInfo.Field1 = txtField1.Text myInfo.Field2 = txtField2.Text ... myController.Update(myInfo...) ... 'Code to send an email message
As excited as I would be to have an automated testing framework complete with lots of green lights, I love it even more when I look at the code and see that it's properly factored and therefore easier to extend and maintain. If I wanted to use the code above for integration, say with a new BlogML piece I'm writing :), or a MetaWeblog implementation, I would have to copy and paste the code from the module and basically create a new service layer. Then I've got duplicate code and a maintenance headache down the road. Operations like AddEntry, where a lot of things need to happen the same way each time (permissions checked, data validated, emails sent, related tables updated) are great candidates for a service layer.
By dworthley on
8/15/2008
|