Innovate faster and cut risk with PHP experts from Zend Services.
See How Zend Helps Leading Hosting Providers Keep Their Managed Sites on Secure PHP
Learn PHP from PHP experts with free, on-demand, and instructor led courses.
Submit support requests and browse self-service resources.
What is PHP code testing, and why should teams commit valuable development time to writing code and configuring testing tools?
For many, the answers to these questions are often learned through painful, drawn out experiences. It could be fixing broken code in production because of a regression. Or it could be watching your team burn up development time modifying legacy code. Or it could be testing and retesting functionality after a PHP migration. These situations can be stressful, time-consuming, and expensive – if you don’t have proper test coverage.
In this blog, we look at the basics of PHP testing, why it’s so important, and the various testing types that combine for full test coverage in a PHP application.
PHP testing is, in essence, writing specific code and scenarios to run your own code in an automated, deterministic, and repeatable way. There are numerous software and frameworks to avoid the hassle of testing boilerplate code.
There are several ways of testing code, depending on the test’s purpose:
The more lines of your code are executed when running your unit tests, the more code coverage you achieve.
Testing your code, whatever the kind of test, is often neglected because producing new code seems more important than testing the one already existing.
But as your codebase grows bigger, tests become not only more important, they become harder to add. This can lead to a point where no one wants to work on the codebase beyond cosmetic changes.
Proper testing coverage gives benefits beyond preventing this type of problem. It also helps to ensure code quality, prevent regression, increase development agility, enhance application security, and makes it easier to pinpoint failure points within your application.
Since low quality code is extremely hard to unit test because of strong coupling, mixing of responsibilities, heavy usage of static expressions, and etc., introducing unit testing in your project will help to enhance code quality. With time, you will even start to think about your tests at the very moment you are writing your code, putting you on the path of test-driven development (TDD).
When you achieve a fair code coverage, introducing a breaking change in your code will break your unit tests thus alerting you and allowing you to fix the issue even before QA team discovers it.
When tests have developers backs, you no longer fear deep code evolution and large refactoring, even in the parts of the code you didn’t write yourself, you know that if you do something wrong, unit tests will fail thus pointing you right to the place where you have to fix your code.
Load and stress testing will allow you to pinpoint and address your Single Point Of Failure (SPOF) long before an unusual audience catastrophically raises them to your knowledge.
Static analysis of your codebase can discover security issues before someone takes advantage of them.
Part of developing unit tests is determining what should and shouldn’t be tested. Some parts of your code won’t need to be directly covered by tests, e.g., best abstract classes, private methods, and protected methods.
These abstract classes, private and protected methods should be extended and called by concrete classes and public methods. So testing these concrete classes and public methods thoroughly will give you a fair coverage. Either, you should not test filesystem (unless you are writing your own), external libraries, or database queries.In the case of filesystem (unless you are writing your own) external libraries, or database queries, you will likely use some specific testing techniques often provided by testing frameworks.
There are several ways of testing your PHP code. Depending on your project criticality, you will have to pick the ones which fit your situation. Once you picked which kind of tests you need to perform, you will also have to decide how extensive these tests need to be.
Knowing you can’t achieve a 100% unit test coverage on your code doesn’t mean you must give up on unit testing. Pick the most critical parts of your application and start covering them step by step. Also, you could decide to enforce a 100% coverage on the new code to be written.
In the next sections, we’ll go over a few of the more popular testing techniques and approaches used for testing PHP applications.
Unit testing is probably the most known and discussed automated code testing technique.
Unit testing consists of writing code which runs your code method by method and function by function (hence the name “unit” test). The goal of unit testing is to see that code runs as intended and in a deterministic way (ie when run with same arguments, code produces the same result).
In unit tests, code is run in isolation, then, you simulate (“mock”) database access, file system, HTTP Requests and external libraries since there is no point in testing code you didn’t write (you should check it has been tested by its developer though!). This also makes these tests very fast to run.
There are a large number of PHP unit testing frameworks that can help you to create unit tests, and to simulate, or mock, filesystems, databases, and etc..
Integration tests on the other hand, will be using database, filesystem and external libraries for real in order to check that your code “integrates” with them.
These tests should be run on a specific environment similar to the production environment, they could be run by hand, but automated tests are far more efficient since they can be run on each code change to avoid regression.
A fair unit test and integration code coverage will protect you from regression during code evolutions or refactoring.
For instance, should you add a dependency injected in the constructor of an object and forget to update the related Factory, if your factory is covered, the test will break, thus avoiding a regression.
Even with a decent coverage, you will most certainly encounter some regressions, when identified and corrected, you will enhance your tests and coverage in order to avoid a new regression during the next refactoring or code evolution.
Profiling your code will allow you to detect high processor and memory footprint, quickly pointing you at the most resource consuming parts of your code.
Performance testing will most of the time be run on a specific part of the code after a load test failed, pointing out a part of the application which performed badly.
Load Testing is performed, most of the time against a staging environment, to assess the global performance of the infrastructure and application under heavy load and determine the maximum load it can handle.
In order to generate the conditions of this extreme load, you will use a software or a framework which will run pre-established scenario against your application.You will increase load (for instance: number of requests per second, number of concurrent users etc.) until one of the components of your application falls down.
Knowing this limit is very important to be able to forecast your capacity to handle peaks like a TV show or an influencer blog post introducing your application or service.
Once you reached the maximum load that your infrastructure and application are able to handle, increasing the load, even slightly, will no longer result in slowing its execution, but in a stress condition: some parts of your infrastructure or application will stop working, often, the first components to fail will be database and filesystem.
Extreme form of stress testing called “chaos monkey” consists in randomly shutting down parts of your infrastructure and application in order to study its overall resilience.
Performing stress tests will allow you to prioritize hardware, network and software enhancements necessary to achieve the next level of load.
Static analysis and SAST tools will walk all the possible execution paths of your code, aiming for poor development practices and security holes then reporting them in a human readable format (replace human by developer...).
“Pen-tests” (penetration tests) is another way of testing your code’s security, you will allow a security company to simulate a cyberattack on your system in order to evaluate its security. You will decide how far the hackers are allowed to go to perform their attack.
Without software and frameworks, performing specialized and complex testing would be a hassle.
Luckily, generations of developers have developed technologies to help deal with this hassle. The biggest problem today is picking the tool that best fits your purpose, skills, and resources. Don’t worry, though, some tools are “one-size-fits-all”.
Lack of good PHP testing practices causes problems. The first step in overcoming those problems is in understanding the impact of poor test coverage.
Ongoing issues like poor performance, recurring bugs, and low development agility can be used as evidence of why proper test coverage is important. And understanding how these issues tie back to test coverage can help opposed parties to see the value in these proactive measures.
There are a multitude of testing methods for software code. Check out the complete guide to testing types. Looking for additional information on PHP testing specifically? This webinar on PHP test automation is worth a watch.
Test coverage is maybe the biggest factor in deciding on a PHP migration for enterprise-scale applications. This white paper looks at why that test coverage is important, and explores the hidden costs that can provided unexpected consequences during PHP development.
Download Free White Paper