Get your FREE 30 page Developing SOLID Applications guide!

How To Test Legacy Applications

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?

Learning design patterns doesn't have to suck.

Design patterns open a whole new world of possibilities. So why are you avoiding them? This brand new book will help you finally understand these wonderful programming techiques!

Learn design patterns TODAY »

Martin Hlaváč (@m_hlavac) wrote at 3/15/2013 5:03 pm:

There is one major problem with Zend. Code built on it uses static calls and if developers on legacy app loved this pattern then one object changes behavior of completely different objects which really makes it hard to test anything.

In this case you have to use functional tests as you mentioned in your post. You have to write functional tests for your application’s frontend anyway, because sometimes unit tests won’t be enough to find some specific problems.

Anyway… great article, keep it comming i like your ideas and way of your programming

Hikari wrote at 4/11/2013 2:47 pm:

I didn’t understand this article at all. By the title, I understood legacy as software that’s already developed, had no test plan, and now must be tested all of a sudden. We’d then need to manually test it all interacting with its UI, or inspect it for strategic places to add automated tests (like find loose coupled classes that can be unit tested).

Then you started explaining a strategy for building a new software architecture that’s test friendly. Isn’t the software finished and legacy? :P

Anyway, I see tests as a very important part of planning and also as the easiest part of specification. I hate testing, so I love automated tests.

In Java it’s very easy to build architectures that are easy to automate tests. Just divide the software in components and immediately design their interfaces, and we’re ready to start developing test units that will run on these interfaces. TDD.

But in PHP it’s way harder. PHP implies outputting to browser and isn’t easy to change output stream. It doesn’t have any sort of logging feature, like java.util.logging. And I myself don’t like these tools that must be added in production code to receive a bool and build a report.

I’d love more articles about testing in PHP!