Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing Legacy PHP Spaghetti Code?

I inherited a fairly large, homemade, php4+MySQL, ecommerce project from developers that literally taught themselves programming and html as they wrote it. (I would shudder except that it's really impressive that they were able to do so much by starting from scratch.) My job is to maintain it and take it forward with new functionality.

Functionality of the code depends on $_SESSION data and other global state structures, which then affect the flow of the code and which parts of the site are displayed through require statements. When I took it over last year, my first task was abstracting all of the repetition into separate files which get included via require statements and also removing most of the 'logic' code from the 'display' or output code, but I couldn't remove it all. I have moved code into functions where I can, but that's still quite limited. Classes and methods are definitely out of the question right now.

All testing is being done manually/visually. I would like to start automating some testing, but I simply don't know where to start. Unit testing of functions is pretty straightforward, but very little of the code is in functions and most of that is pretty simple. I've looked at phpUnit and DbUnit, but all of the examples and discussion about them focus on classes and methods.

So, what options do I have to begin implementing unit testing on anything more than the most trivial parts of my project?

like image 350
Clayton Avatar asked Dec 22 '11 17:12

Clayton


3 Answers

First off PHPUnit can be used to test procedural code just fine. Don't let the fact that PHPUnit examples only shows classes deter you. It's just how PHPUnit tests are organized.

You can just write test classes and test your function from them without any problems and that should be your smallest problem :)

If the code doesn't run on PHP 5.2+ then you can't use a current PHPUnit Version which is definitely more of a concern and my first general recommendation is to find any issues an PHP 5 upgrade might bring.


To start off one book recommendation to save you some troubles:

Working Effectively with Legacy Code

The book will help you avoid a lot of small mistakes you'd have to make yourself once instead and will get you in the right mindset. It's Java based but that is not really an issue as most of the stuff is easily adaptable.


Testing is hard because you don't even know what the application is supposed to in the first place

Getting unit tests up an running takes quite some time and doesn't give you a status "is it still working" so my first point would be to get some integration and front-end tests set up.

Tools like Selenium and the web testing parts of Behat can help you A LOT with this.

The advantage of using Behat would be that you can write nice documentation for what the product actually is supposed to do. No matter how to project goes along these docs will always have value for you.

The rests read something like: "When I go to this url and enter that data a user should be created and when I click there I get an email containing my data export". Check it out. It might be useful.


The most important thing is to get a quick green/red indicator if the thing is still working!

If you then find out that it was broken despite your "light" being green you can expand the tests from there on out.


When you don't know when it is broken you will never be confident enough to change enough stuff around so that you can incrementally improve what needs fixing or changing.


After you have a general sense of how everything work and you trust your small tests to show you when you break "the whole thing" I'd say it's time to set up a small Continuous integration server like Jenkins for PHP that allows you to track the status of your project over time. You don't need all the QA stuff at the start (maybe to get an overview over the project) but just seeing that all the "does it still work" stuff returns "yes" is very important and saves you lots of timing making sure of that manually.

2% Code Coverage is boring

When you are at a point where unit testing and code coverage come into play you will be faced with a mean read 0%. That can be quite annoying to never see this number rise a lot.

But you want to make sure you test NEW code so I'd suggest using PHP_Change_Coverage as described in this blog posting so make sure everything you touch has tests afterwards.

PHP Black Magic

function stuff() {
    if(SOME_OLD_UGLY_CONST == "SOME SETTING") {
         die("For whatever reasons");
    }
    return "useful stuff";
}

When testing it is really annoying when your scripts die() but what to do?

Reworking all scripts without tests can be more hurtful than not doing anything at all so maybe you want to hack to get tests first.

For this an other solutions to scary things there is the php test helpers extension.

<?php
set_exit_overload(function() { return FALSE; }
exit;
print 'We did not exit.';
unset_exit_overload();
exit;
print 'We exited and this will not be printed.';
?>
like image 72
edorian Avatar answered Nov 06 '22 11:11

edorian


I would probably start testing with a tool like Watir or Selenium. This will allow you to do black box testing of the the whole page automatically. Once you have set up these tests, you can start to refactor the PHP pages, and build up unit tests as you are doing the refactoring.

like image 6
Brian Hoover Avatar answered Nov 06 '22 13:11

Brian Hoover


Legacy code without unit tests is always a pain. There's no real solution because most of the time the code isn't written in a way it's unit testable at all. At work we had to handle lots of legacy code too. We wrote unit tests for new written code (which is a pain too, because you need to be able to set up some test data and stuff like that). This way it doesn't get worse and you will cover more and more old legacy code that is called within your new code. Doing this you will get closer each time to code that is covered by unit tests.

like image 2
ChristopherS Avatar answered Nov 06 '22 12:11

ChristopherS