Dino Esposito is a trainer and consultant who specializes in Microsoft .NET technologies. He can be contacted at [email protected]
Software testing is the process of checking software to ensure that it behaves as expected, is free of errors, and satisfies its requirements. A software test verifies that a given component returns the correct output in response to a given input and a given internal state. Having control over the input and the state, and being able to observe the output, is essential for a successful and reliable test. If you could automate the process with a tailor-made application, that would be ideal, and that's what unit testing is all about.
Microsoft's ASP.NET Web development framework is limited when it comes to producing testable products. It doesn't prevent unit testing per se, but because ASP.NET Web Forms applications are based on pages, testing them requires you to arrange ad hoc HTTP requests and send them to each page. You then observe the response and ensure that it matches your expectation. But the output of a page is HTML, a potentially long string of text with multiple possible -- and equally valid -- representations. In addition, testing an ASP.NET page means spinning up the entire ASP.NET runtime.
Testing isn't easy in these conditions. A testable page has an internal architecture that applies the principle of Separation of Concerns (SoC) in which the application is separated into distinct components while living in a runtime environment that allows the mocking of some of its components for testing purposes. This is doable, but it isn't facilitated in ASP.NET Web Forms. Consequently, many developers end up testing their sites simply by poking around.
A couple of anti-patterns, which describe what not to do, relate to testing practices. The Test-By-Release anti-pattern refers to releasing a software product without paying much attention to time-consuming chores such as unit and integration testing. Because users are the final recipients of the product, the pattern gives them the last word on whether the software works. The Test-By-Poking-Around anti-pattern refers to taking a tour around the product's feature set, and tracking and fixing errors and misbehavior that pop up. At minimum, these anti-patterns are based on non-repeatable sequences which makes it hard to catch regression failures.
The level of SoC and testability in an ASP.NET solution can be raised by redesigning the content of the code-behind class -- that is, the separate class file that ties together a page's procedural code. By extensively using the Model-View-Presenter (MVP) pattern, you can take a large share of the page logic out of the code-behind classes.
Once the logic lives in its own presenter class, it can be easily tested in isolation with no dependencies on the runtime environment. As for testability, the ASP.NET runtime environment isn't designed with testability in mind. The HTTP context can't be easily mocked to a custom object. To automate tests on an ASP.NET page you likely need a commercial or homemade made-to-measure tool that prepares in the background HTTP requests and determines a way to check returned values or markup.
ASP.NET MVC is a relatively new platform for building ASP.NET applications. Based on the same runtime environment as classic ASP.NET Web Forms, ASP.NET MVC makes developing Web applications a significantly different experience. In ASP.NET MVC, you build applications focusing on the action to take and the component -- the controller -- that will execute it. The controller's code is exclusively focused on executing the action and isn't mixed up with generation of the UI. This separation keeps the view code thin and simple; it also makes it easy to test the controller.
Atop the standard ASP.NET runtime environment, ASP.NET MVC builds its own shell of functionalities and injects intrinsic objects, mimicking those of the ASP.NET runtime. Interestingly, these intrinsic objects wrap ASP.NET native intrinsics at runtime but can be mocked with plain classes that have no dependencies during tests.
ASP.NET Web Forms can be bent to some extent to achieve more testability. However, if you want true and full testability and are willing to tackle the challenges of a relatively immature platform, switch to ASP.NET MVC.