tl;dr Periodically empty out the uploads directory in your WordPress dev environment to speed up PHPUnit tests.
Over the past few months of working on the AMP plugin for WordPress, I’ve been noticing that PHPUnit has been running slower and slower over time. Well, today this frog jumped out of the boiling water: I decided to figure out what was causing it to run so slow—over 10 seconds to run a single test case.
At first I thought some tests were making HTTP requests and this was why it was slow. There were indeed some requests being made, but even after mocking the HTTP requests to prevent hitting the network the tests were still slow to initialize.
I turned to XDebug profiling to figure out what was going on. In my VVV environment I edited the PHP config file for Xdebug:
sudo nano /etc/php/7.0/cli/conf.d/20-xdebug.ini
I went down to find the xdebug.profiler_enable
configuration:
; xdebug.profiler_enable ; Type: integer, Default value: 0 ; Enables Xdebug's profiler which creates files in the profile output directory. Those files can be ; read by KCacheGrind to visualize your data. This setting can not be set in your script with ini_set ; (). xdebug.profiler_enable = 0
And I switched the value from 0
to 1
and saved:
xdebug.profiler_enable = 1
I then ran phpunit
for the plugin (after having already run xdebug_on
) and this generated a couple files in the VM’s /tmp
directory:
cachegrind.out.1530400695-_usr_local_src_composer_vendor_phpunit_phpunit_phpunit
cachegrind.out.1530400695-_srv_www_wordpress-develop_public_html_tests_phpunit_includes_install_php
I copied these from the VM into a shared directory that I can access from my host machine. I opened the “phpunit” cachegrind file via PhpStorm’s builtin Cachegrind viewer (“Analyze Xdebug Profiler Snapshot”) and it quickly revealed what the problem was:
Blame: WP_UnitTestCase::scan_user_uploads()
. Seeing how this method is called also explains why there was only the delay before the first unit test is run, since it only scans for uploads the first time a test is setUp
. If I comment out the calling of that method then that seconds-long delay between installing and the first test running is eliminated. It turns out I had 6,000+ files in my uploads directory so it makes sense why it was slow. In my dev environment these uploaded files accumulate over time when testing features, and given that I have upload directories going back to 2010 it’s clear I don’t clean them out enough.
My development environment is running wordpress-develop from source, where unit tests run in-place alongside non-test data. A separate database is used during unit tests, but the files are the same (other than the WP config). So the uploaded files in question here are not files that are added during unit testing—such files should get deleted automatically at tearDown
. Rather, these files are ones uploaded by my own manual testing in the course of using the site as an end user.
So the quick fix is to just empty out your uploads directory.