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 helper for testing in WordPress.

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

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

/**
 * We need to include autoloader to use our plugin
 * and to use Brain Monkey for running 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 warning
   */
  public function test_silence_warning() {
    $this->assertTrue( true, true );
  }
}

In the root of your project add phpunit.xml.dist

<?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 setup our plugin’s unit tests. If you don't have WP-CLI installed on your system, install it. There is a documentation on starting unit tests which you can find 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 it 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 setup the test database. Be sure that your mysql service is up and running if you're running tests outside of VVV.

After that you can run the plugin tests by writing

vendor/bin/phpunit

The WP-CLI only provides 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 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 that 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. Then the phpunit should work.

Xdebugg inside VVV

For some reason, when Xdebugg is enabled in the VVV, when you run unit tests, and want to have the coverage generated, it will take an extreme amount of time to check it. In that case either disable creating code coverage

phpunit --no-coverage

Or run the test outside the VVV. Running tests outside of VVV with Xdebug is significantly faster (fev sec vs ~10 minutes).