0

I have a web application which currently exists as a single large class containing a front controller, and a bootstrap file which runs the class and passes in the settings.

Over time, the class has become over-large, with multiple concerns, that I have long wanted to refactor into what will be rather obvious subclasses. I'm very familiar with all kinds of refactorings.

However, for this application, at present there is no test coverage. Because all interactions are done by reading GET and POST parameters, there is only one public method into the system, i.e. such URL interactions through the front controller entry point. So the class is hard to unit test (I will be using PHPUnit) as it stands.

Obviously it is far safer to refactor with tests already in place. So I would welcome views on which strategy is best:

1) Create a pile of tests that implement GET and POST interactions as per a user using the web application; or

2) Create a pile of tests against the private functions by using the ReflectionClass workaround, and convert these to standard PHPUnit tests concurrently with the refactoring; or

3) Add unit testing after doing the subclass refactoring, testing the public entry API points to the new subclasses.

Community
  • 1
  • 1
fooquency
  • 1,575
  • 3
  • 16
  • 29

1 Answers1

0

Either way how you approach it, I would do it one-functionality at a time if you can, it makes the task less daunting and therefore more achievable...

When confronted with such situations in the past (quite a few times in fact), I usually do this:

First of all, does the application use external dependencies like databases? The first thing is that we need to make these predictable. I usually try to find where the creation of these external dependencies occur and then delegate it to a good Dependency Injection framework (like Pimple).

Once that is done you can add rules to the DI factory methods that return test databases depending on some conditions set: I usually use a test domain for this, so if the site is foo.local then i also have a domain test.foo.local that sets (in the Apache config for example) an environment variable APPLICATION_ENV set to 'tests'. The DI container can then inspect this environment variable to serve the right dependency, in our case a connection pointing to a test database.

(It don't like that production code is aware of that it might be in a test scenario, but it's a lesser evil, and it can be alleviated by using config files that have the environment variable in the filename for example. I digress.)

When this is done, in my tests I then have a reference to the same test database which I then use to set up some predictable test data with some thing like DbUnit or test-db-acle (disclaimer, I wrote the latter one, so I tend towards that).

Once the test data is in place, I issue a request to the url in question with something like Guzzle (in various important variations) and record the output(s), which I then use to make a test that sets the behaviour 'in stone'. NOTE: this is a very imprecise method, the best way for tests is in a test-driven way, but this is not a solution in this case obviously. However, if you are reasonable sure that some manual testing has been done on this, then this is a good way to at least get a few smoke tests into place. In my experience the value of having even one rudimentary smoke test in place is infinitely more valuable than not having any.

Now that you have a smoke test in place, you can refactor this part of the application and move to a new one.

I hope this help....

malte
  • 1,439
  • 1
  • 11
  • 12