Automated testing

Setting up tests for WordPress is relatively easy. First, you need to add "phpunit/phpunit": "^6.5" and "brain/monkey": "^2.2" to your composer require-dev part in composer.json.

Or you can add it from the terminal:

composer require --dev brain/monkey:2.2
composer require --dev phpunit/phpunit:6.5

This will load PHPUnit and Brain Monkey. PHPUnit is the testing suite, and Brain Monkey is a helper for testing in WordPress.

After that, in the tests folder add the bootstrap.php file that looks like this:

<?php
/**
 * PHPUnit bootstrap file
 *
 * @package My_Project
 */

/**
 * We need to include autoloader to use our plugin
 * and to use Brain Monkey for running a unit test.
 */
require_once dirname( dirname( __FILE__ ) ) . '/vendor/autoload.php';

And dump your autoload to load all the necessary classess and files. It's also good to add the init class that you'll extend called init-setup.php

<?php
/**
 * Class Init tests
 *
 * @package My_Project\Tests
 */

namespace My_Project\Tests;

use PHPUnit\Framework\TestCase;
use Brain\Monkey;

class InitTestCase extends TestCase {
  /**
   * Setup method necessary for Brain Monkey to function
   */
  protected function setUp() {
    parent::setUp();
    Monkey\setUp();
  }

  /**
   * Teardown method necessary for Brain Monkey to function
   */
  protected function tearDown() {
    Monkey\tearDown();
    parent::tearDown();
  }

  /**
   * This method is only set to silence warnings
   */
  public function test_silence_warning() {
    $this->assertTrue( true, true );
  }
}

Add phpunit.xml.dist in the root of your project.

<?xml version="1.0"?>
<phpunit
  bootstrap="tests/bootstrap.php"
  backupGlobals="false"
  colors="true"
  convertErrorsToExceptions="true"
  convertNoticesToExceptions="true"
  convertWarningsToExceptions="true"
  >
  <testsuites>
    <testsuite>
      <directory prefix="test-" suffix=".php">./tests/</directory>
    </testsuite>
  </testsuites>
  <filter>
    <whitelist>
      <directory>./</directory>
      <exclude>
        <directory>./node_modules</directory>
        <directory>./vendor</directory>
        <directory>./tests</directory>
      </exclude>
    </whitelist>
  </filter>
  <logging>
    <log type="coverage-clover" target="tests/_reports/logs/clover.xml"/>
    <log type="coverage-html" target="tests/_reports/coverage" charset="UTF-8" yui="true" highlight="true" lowUpperBound="35" highLowerBound="70" />
  </logging>
</phpunit>

Plugin testing

Use WP-CLI to set up our plugin’s unit tests. If you don't have WP-CLI installed on your system, install it. Documentation on starting unit tests can be found here.

Assuming you have a plugin on your testing environment, in the project root folder run

wp scaffold plugin-tests my-plugin

This will create several new files and folders in your plugin.

bin/
    install-wp-tests.sh
tests/
    bootstrap.php
    test-sample.php
phpunit.xml
.travis.yml

To initialize the testing environment locally, go to your plugin directory and run the install script:

bin/install-wp-tests.sh wordpress_unit_tests root '' localhost latest

The install script first installs a copy of WordPress in the /tmp directory (by default) as well as the WordPress unit testing tools. Then it creates a database to be used while running tests. The parameters that are passed to install-wp-tests.sh set up the test database. Be sure that your mysql service is up and running if you're running tests outside VVV.

After that, you can run plugin tests by writing:

vendor/bin/phpunit

The WP-CLI provides only one sample test

class SampleTest extends WP_UnitTestCase {

  /**
   * A single example test.
   */
  function test_sample() {
    // Replace this with some actual testing code.
    $this->assertTrue( true );
  }
}

So you'll need to write your own tests.

Debugging inside tests

If you want to check the output of a variable inside your test, just add

fwrite( STDERR, print_r( $variable, true ) );

Possible issues

Require error

When running phpunit for your plugin outside VVV, you get an error that looks like this

Warning: require_once(.../wordpress//wp-includes/class-phpmailer.php): failed to open stream: No such file or directory in .../wordpress-tests-lib/includes/mock-mailer.php on line 2

Fatal error: require_once(): Failed opening required '.../wordpress//wp-includes/class-phpmailer.php' (include_path='.:/opt/lampp/lib/php') in .../wordpress-tests-lib/includes/mock-mailer.php on line 2

In this case, delete the database (using Sequel Pro or via terminal), delete the temporary folder where WordPress is installed (either in /tmp/wordpress/ or somewhere in /var/folders/.. subfolders), and run

bash bin/install-wp-tests.sh wordpress_test root '' localhost latest

in the terminal. After that, phpunit should work.

Xdebugg inside VVV

For some reason, when Xdebugg is enabled in VVV, and you want to have coverage generated when running unit test, it will take extremely long to check it. In that case, either disable creating code coverage

phpunit --no-coverage

or run the test outside VVV. Running tests outside VVV with Xdebug is significantly faster (a few seconds vs ~10 minutes).