Automated Testing of ASP.NET MVC Applications
By: Artëm Smirnov
For many years the developers who practiced Unit Testing were frustrated about numerous problems they had when trying to apply automated testing to ASP.NET sites, in particular, those that were built using the WebForms framework (which was, for many, a synonym of ASP.NET). Not so long ago, Microsoft developed a new ASP.NET framework, called ASP.NET MVC. One of the selling points of this framework was its testability. In this article, we’re discussing what the problems are with testing ASP.NET sites in general, and how the ASP.NET MVC framework tries to solve them.
What’s different about testing ASP.NET applications?
When you are developing a library, or an application, you "own" the code. It means that, provided you follow certain guidelines, you can automate testing all, or at least all worth testing, features of your product. While you usually use third party libraries, or system resources like database or Internet connection, they can be considered "enhancements" sitting on top of your code.
With ASP.NET, the situation is reversed. What you develop are, essentially, enhancements to the IIS (or another hosting process). This is not unique, of course, to ASP.NET – the same holds true for any plugin development. It is like your code is a "guest" in this system, and should behave accordingly. You can add as many classes as you wish, and make them testable, but there is always a boundary layer that communicates with the framework. The host system creates these boundary classes, and calls certain methods that you provide, so that you have a brief moment of control. In WebForms, this layer is made of ASPX pages and code-behind files. In ASP.NET MVC, it is Controllers and Views.
For testing, a developer can take two very distinct paths. A developer can either test the main system together with your custom code (integration testing), or test your code in isolation, somehow dealing with the absence of the main system (unit testing).
End-to-end, or integration, tests verify the behavior of the system as a whole. One can start, for example, with a certain URL, and inspect the HTML output, plus the side effects (a DB record inserted, an email sent, some money written off of our account, etc). Based on this test, we can assume that everything works as expected, or something is wrong. Given the HTML response, for example, all we can is search for a certain string and hope that if we find it, then everything else is as expected as well. If not, we have an idea that something went wrong, but we don't know what. This is known as a "black box" testing – we provide an input and inspect the output, but we don’t know what’s inside.
We can push this even further, and test our client code together with the server code. While the former tests mimic a browser (set up an HTTP request, inspect the response), the latter ones mimic a user ("click" a button, inspect the content of a certain HTML element). Typically, we write code that "drives" a browser, automating all the clicking for us. There are some important qualities that characterize such tests:
* We are testing the system behavior as it is presented to the end user, so if the tests pass, the system is expected to work correctly.
* If a test is broken, we don't know whether it is a problem with the client or the server code, or the incompatibility between these two.
* Such tests are really slow. The clicking happens faster than a human would do it, but still much slower than the code processing. A complex system can take several hours to test.
* Complicated setup and cleanup: Often we have to perform several steps before we even get to the page we want to test. For example, testing a password protected page would require visiting the login page first.
* Tests are hard to maintain, as there is a lot of test code involved that is not directly related to the system.
Whether we use client code testing or not, there are some general problems with such tests, and these problems do not depend on a particular framework or programming language:
* If something’s wrong, we are not sure about what needs to be fixed.
* More often than not, some tests start to fail because of a non-functional change (such as changing an ID of an HTML tag).
* It is hard to control the external dependencies. For example, if we test an e-commerce application, we don’t want to bill somebody’s account each time we run a test, yet we need to get a positive response from the billing system, so that we can feed it into our system.
* Integration tests alone do not drive your system to a better design. After all, they don’t care about the implementation.
So, while integration tests are very important, and should be a part of any test suite in order to ensure that your system works properly as a whole, it is essential to use unit testing in your development process.
... to read more articles, visit http://sqa.fyicenter.com/art/