How To Test Legacy Applications
Out Of Date Warning
Languages change. Perspectives are different. Ideas move on. This article was published on March 13, 2013 which is more than two years ago. It may be out of date. You should verify that technical information in this article is still current before relying upon it for your own purposes.
You’re ready to start testing your application. But there’s a problem: the application is a legacy application, or based on a framework. The code is rickety and the level of the code is less than S.O.L.I.D. Is it possible to correctly unit test the application? You want to have certainty that fixing one bug won’t produce another. How do you move forward?
For a few months now I offered Five Tips For Developing Awesome Software. These tips start with an admonition to “test everything”. This is important, because unit testing is one of the easiest ways to ensure that your changes in one part of the application won’t break another part of the application. Unfortunately, as one user told me, legacy apps are notoriously bad for unit testing, because they were either developed before unit testing was a wide practice in PHP, or they use frameworks that don’t encourage unit testing at all.
But this is no reason to give up. It is possible to unit test these apps. Here’s how.
Focus the business logic in the model
Frameworks like Zend Framework encourage developers to create their own models that are largely independent from the rest of the application. This is a huge benefit to developers who want to write unit tests, because the fewer the dependencies in the code, the better.
Developers can take advantage of this dependency-free environment and focus most of their business and validation logic in the model. The benefit of doing this is that the low number of dependencies is easier to test, and the developer can execute true unit tests instead of functional tests.
Also, by placing the logic into the model developers have a pre-made layer that can be used in any number of ways, most notably for creating a JSON or REST API. For example, if the model contains the majority of the business and validation logic, then the controller and view layers are responsible almost exclusively for passing data around and display logic. These can easily be converted into API components.
Create libraries that can be accessed by framework components
Developers often include their logic in controllers or views. However, these functions cannot be tested easily without invoking the other components of the application.
The solution to this is to create outside libraries that stand alone, and are accessed by the controller or the view.
For example, if you are developing a component that speaks to a service, build it as a library rather than writing the code directly into the controller. Not only will the code be reusable (a major win) but it will be testable because it does not rely upon the dependencies in the framework.
Accept that functional tests may be necessary
When using a framework, it’s nearly impossible to fully unit test all the code in the application. This doesn’t mean that testing is impossible though: functional testing is a valid form of testing, when used in conjunction with unit testing.
Unit testing tests individual bits of code in isolation. Functional testing, on the other hand, tests code and how it relates to the overall application. While unit testing is useful for identifying specific units that have failed, functional testing can provide an overall analysis of the code in order to tell developers whether or not the application is still working.
For components that cannot be decoupled from the database, functional testing may be the only option. Similarly, for components of the framework like the controller, which cannot be decoupled from the framework itself, functional testing makes the most sense.
What are your legacy application testing strategies?