How to reduce your PHP tests execution time up to 85%

The solution relies on the use of ParaTest, a library that supports parallel testing in PHPUnit.

Speedometer image from [Wikimedia](https://upload.wikimedia.org/wikipedia/commons/6/65/Speedometer_%28kmh%29.JPG)

Speedometer image from Wikimedia

We all know that a good test suite — unit and integration — is important to any application. We also know that running all our tests can take some time (especially in large projects). What one may not know is that is possible to reduce this time up to 85% (or even more).

In this post, I will show how we did this. Results may vary, but certainly you will notice a great improvement.

The Problem

In my squad’s current project, we have (at this time) a test suite with 345 scenarios (865 assertions). It was taking almost 4 minutes to finish the whole execution.

During Brayan’s researches, he found a package that could help us by reducing the time on this task. He thought it could be a good idea for a Pet Project Day and I decided to help him on it.

The Implementation

The solution relies on the use of ParaTest, a library that supports parallel testing in PHPUnit. So, instead of running just only one process, the idea is to distribute your tests into several different threads.

Even if you try the default usage (no additional parameters) you will be able to see some improvements already.

However, the real magic comes if you configure the runner parameter, as explained in the ParaTest documentation:

The default Runner for PHPUnit spawns a new process for each testcase. This provides the highest compatibility but comes with the cost of many spawned processes and a bootstrapping for each process. Especially when you have a slow bootstrapping in your tests (like a database setup) you should try the WrapperRunner with --runner WrapperRunner or the SqliteRunner with --runner SqliteRunner. It spawns one “worker”-process for each parallel process (-p), executes the bootstrapping once and reuses these processes for each test executed. That way the overhead of process spawning and bootstrapping is reduced to the minimum.

Besides that, you can tweak even more by changing the amount of processes created. The default is the number of logical CPU cores of your machine. You should take into account that each process generates some overhead though. That’s why you need to resist to the temptation of creating a massive number of threads.

Therefore, in our scenario, the optimal configuration was:

Results

By doing this, we’ve managed to achieve the following:

Before

After

Basically, we are 7 times faster than before, or using just 14% of the original time!

Isn’t that amazing?

An additional improvement is the reduction of memory usage as well (from 66MB to 34MB).

Conclusion

Less time during the build process means more efficient use of resources and a faster deployment. And all of it was achieved by simply installing a new package.

Do you have any other ideas on how to improve the build process? Let us know in the comments!


This post was originally published on THE ICONIC Tech blog.