Title: Writing PHP Tests
Author: Boone Gorges
Published: August 30, 2017
Last modified: May 9, 2024

---

# Writing PHP Tests

## In this article

 * [About the WordPress PHPUnit Test Suite](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#about-the-wordpress-phpunit-test-suite)
 * [The Basic Structure of a Test](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#the-basic-structure-of-a-test)
    - [Assertions](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#assertions)
    - [Fixtures and Factories](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#fixtures-and-factories)
 * [Shared Fixtures](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#shared-fixtures)
 * [Using Assertions](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#using-assertions)
 * [Annotations](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#annotations)
 * [Naming and Organization](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#naming-and-organization)
    - [Test Classes](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#test-classes)
    - [Test Methods](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#test-methods)
 * [Advanced Topics](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#advanced-topics)
    - [Slow Fixtures](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#slow-fixtures)
    - [Repetitive Tests](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#repetitive-tests)
    - [One-off Functions for Hooks](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#one-off-functions-for-hooks)
 * [Technical Overview](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#technical-overview)
    - [The WordPress Installation and Bootstrap](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#the-wordpress-installation-and-bootstrap)
    - [Globals](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#globals)
    - [Database](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#database)

[↑ Back to top](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#wp--skip-link--target)

## 󠀁[About the WordPress PHPUnit Test Suite](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#about-the-wordpress-phpunit-test-suite)󠁿

The WordPress PHPUnit Test Suite contains thousands of **automated tests**. Automated
tests are small bits of code that verify a specific piece of WP functionality. These
tests are a powerful tool both for feature development and for the prevention of
regressions.

Automated tests should be as small and as specific as possible. Ideally, an automated
test will be a **unit testunit test Code written to test a small piece of code or
functionality within a larger application. Everything from themes to WordPress core
have a series of unit tests. Also see [regression](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#regression).**:
a test that verifies a piece of functionality in complete isolation, without any
dependency on the overall state of the system. In practice, the structure of WordPress
and its test suite makes it difficult or impossible to write “pure” unit tests. 
Here and elsewhere, we use the term “unit test” to refer loosely to any automated
test in the suite.

## 󠀁[The Basic Structure of a Test](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#the-basic-structure-of-a-test)󠁿

### 󠀁[Assertions](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#assertions)󠁿

The most important part of any test is the **assertion**. An assertion is a comparison
between the value you _expect_ to get from the system, and the value that you _actually_
get. The very simplest tests may consist of nothing but a single assertion. Example:

    ```notranslate
    public function test_trailingslashit_should_add_slash_when_none_is_present() {
    	$this->assertSame( 'foo/', trailingslashit( 'foo' ) );
    }
    ```

The `assertSame()` method accepts two parameters: the _expected value_ (in this 
case, the hardcoded string `'foo/'`), and the _actual value_ (the value returned
by `trailingslashit()`).

An [annotated list of common assertions](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#using-assertions)
can be found below.

### 󠀁[Fixtures and Factories](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#fixtures-and-factories)󠁿

Many tests require the existence of one or more data objects, like posts or users,
that WordPress normally stores in the database. Each individual test method begins
with an empty WordPress installation, so each test is responsible for creating its
own objects for testing. These objects are called **fixtures**, and they are generated
by **factories**.

    ```notranslate
    public function test_user_with_editor_role_can_edit_others_posts() {
    	$user_id = self::factory()->user->create( array(
    		'role' => 'editor',
    	) );

    	$this->assertTrue( user_can( $user_id, 'edit_others_posts' ) );
    }
    ```

The `create()` factory method returns the numeric ID of the object. To get the object
instead, use `create_and_get()`:

    ```notranslate
    public function test_user_exists() {
    	$user = self::factory()->user->create_and_get();

    	$this->assertTrue( $user->exists() );
    }
    ```

Some tests require more than one object of a given kind. In this case, use `create_many()`,
which uses an iterator to ensure object uniqueness (for example, unique email addresses
in the case of users):

    ```notranslate
    public function test_term_query_count() {
    	$tags = self::factory()->term->create_many( 3, array(
    		'taxonomy' => 'post_tag',
    	) );

    	$term_query = new WP_Term_Query();
    	$actual = $term_query->query( array(
    		'taxonomy' => 'post_tag',
    		'fields' => 'count',
    	) );

    	$this->assertSame( 3, $actual );
    }
    ```

Factory `create*()` methods accept an array of arguments, specific to that object
type. For more details, see the `__construct()` method of each factory class at 
https://core.trac.wordpress.org/browser/trunk/tests/phpunit/includes/factory.

## 󠀁[Shared Fixtures](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#shared-fixtures)󠁿

When all tests within a test class need the same fixtures to be available, it is
common practice to abstract the creation of these fixtures out to a “set up” method.
It is also good practice, to clean up after your test and remove any fixtures you
have created.

[PHPUnit offers four methods](https://docs.phpunit.de/en/9.6/fixtures.html) which
are automatically called to help with this: `setUpBeforeClass()`, `setUp()`, `tearDown()`
and `tearDownAfterClass()`.

In the context of the WordPress test suite, `snake_case` versions of these methods**
MUST** be used. These _snake\_case_ methods provide PHPUnit cross-version compatibility.

| PHPUnit method name | WordPress method name | 
| `setUpBeforeClass()` | `set_up_before_class()` | 
| `setUp()` | `set_up()` | 
| `assertPreConditions()` | `assert_pre_conditions()` | 
| `assertPostConditions()` | `assert_post_conditions()` | 
| `tearDown()` | `tear_down()` | 
| `tearDownAfterClass()` | `tear_down_after_class()` |

Functionality in a `set_up()` method will run before each test in a class, while
anything in a `tear_down()` method will run immediately after each test in the class.
In contrast, the `set_up_before_class()` method will run once before the class is
instantiated and the `tear_down_after_class()` will run once after all tests in 
the class have been run.

By default, all test classes in the WordPress test suite extend from the `WP_UnitTestCase`
class which inherits from the [`WP_UnitTestCase_Base`](https://core.trac.wordpress.org/browser/trunk/tests/phpunit/includes/abstract-testcase.php)
class.

The `WP_UnitTestCase_Base` class already contains generic declarations of these 
fixture methods, which do things like: reset the database to its default state, 
clean up post types, taxonomies, some global variables, the registered hooksHooks
In WordPress theme and development, hooks are functions that can be applied to an
action or a Filter in WordPress. Actions are functions performed when a certain 
event occurs in WordPress. Filters allow you to modify certain functions. Arguments
used to hook both filters and actions look the same. etc.

When declaring a `set_up()` method in a test class, it is **critical** that the 
first line of the `set_up()` method is a call to `parent::set_up()`. Similarly, `
tear_down()` methods should always call `parent::tear_down()` as the very last line.

    ```notranslate
    class Tests_Subset_functionName {
    	public function set_up() {
    		parent::set_up();
    		// The specific set up for the tests within this class.
    	}

    	public function tear_down() {
    		// Clean up specific to the tests within this class.
    		parent::tear_down();
    	}
    }
    ```

For more information about when to use which method, please read through the [Fixtures chapter in the PHPUnit manual](https://docs.phpunit.de/en/9.6/fixtures.html).

## 󠀁[Using Assertions](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#using-assertions)󠁿

The most basic assertion available in PHPUnit is `assertSame()`, which performs 
a strict equality check `===` between the `$expected` and `$actual` parameters. 
Nearly any test can be written using this assertion.

For convenience, PHPUnit makes many more assertion methods available. It is strongly
recommended to use the most specific assertion available. See [the official documentation](https://docs.phpunit.de/en/9.6/assertions.html)
for information. As of WP 5.9, all assertions as available in PHPUnit 9.x can be
used in the WordPress test suite and will work PHPUnit cross-version.

Some of the more common assertion methods:

 * `assertContains()` and `assertNotContains()`
 * `assertStringContainsString()` and `assertStringNotContainsString()`
 * `assertTrue()` and `assertFalse()`
 * `assertNull()`, `assertEmpty()`, `assertNotEmpty()`

In addition to assertion methods offered by PHPUnit, WordPress has a number of custom
assertions method available:

 * `assertEqualSets( $expected, $actual, $message = '' )` – Asserts the equivalence
   of two arrays, ignoring order and strict equality (eg `assertEqualSets( [ 1, 
   2 ], [ '2', '1' ] )`)
 * `assertEqualSetsWithIndex( $expected, $actual, $message = '' )`
 * `assertSameSets( $expected, $actual, $message = '' )`
 * `assertSameSetsWithIndex( $expected, $actual, $message = '' )`
 * `assertWPError( $actual, $message = '' )` and `assertNotWPError( $actual, $message
   = '' )`
 * `assertIXRError( $actual, $message = '' )` and `assertNotIXRError( $actual, $
   message = '' )`
 * `assertEqualFields( $object, $fields, $message = '' )`
 * `assertDiscardWhitespace( $expected, $actual, $message = '' )`
 * `assertSameIgnoreEOL( $expected, $actual, $message = '' )`
 * ` assertNonEmptyMultidimensionalArray( $array, $message = '' )`

See a complete list in the [`WP_UnitTestCase_Base`](https://core.trac.wordpress.org/browser/trunk/tests/phpunit/includes/abstract-testcase.php)
class.

All PHPUnit assertions, as well as all WordPress custom assertions, allow for a `
$message` parameter to be passed. This message will be displayed when the assertion
fails and can help immensely when debugging a test. This parameter should always
be used if more than one assertion is used in a test method.

    ```notranslate
    class Tests_Foo {
    	public function test_function_call() {
    		$actual = function_call();

    		$this->assertIsArray( $actual, 'Return value of function_call() is not an array' );
    		$this->assertArrayHasKey( 'desired_key', $actual, 'Key "desired_key" does not exist in array returned by function_call()' );
    		$this->assertSame( 'expected_value', $actual['desired_key'], 'Value for array key "desired_key" does not match expectations' );
    	}
    }
    ```

## 󠀁[Annotations](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#annotations)󠁿

[PHPUnit annotations](https://docs.phpunit.de/en/9.6/annotations.html) are pieces
of metadata, indicated by a `@`, placed in the docblockdocblock (phpdoc, xref, inline
docs) of a test method or class. WordPress’s tests use a number of PHPUnit annotations,
as well as a few custom ones, to organize its tests. Note that annotations belonging
to a class are automatically inherited by all member test methods, and should not
be appended with a full stop.

Some of the more commonly used annotations:

 * `@group` – Used to sort tests and test classes by functionality, into groups 
   that can be run separately (eg `$ phpunit --group comment`). All test classes
   should have at least one `@group` annotation, and individual tests should have
   additional `@group` annotations as necessary.
 * `@covers` – Used to annotate which function, method or class is actually being
   tested by a particular test. It is **strongly recommended** to add a `@covers`
   tagtag A directory in Subversion. WordPress uses tags to store a single snapshot
   of a version (3.6, 3.6.1, etc.), the common convention of tags in version control
   systems. (Not to be confused with post tags.) for every test.
 * `@requires` – This annotation is used to indicate that a test has a dependency
   on, for instance, a specific PHPPHP The web scripting language in which WordPress
   is primarily architected. WordPress requires PHP 7.4 or higher (minimum) version,
   a PHP extension or a particular function being available. If a test can only 
   succeed if such a dependency exists and is fulfilled, the `@requires` tag should
   be added to the test docblock. The [PHPUnit manual](https://docs.phpunit.de/en/9.6/incomplete-and-skipped-tests.html#incomplete-and-skipped-tests-requires-tables-api)
   has some great examples of how to use this tag.
 * `@ticket` – A custom WordPress annotation. Use `@ticket 12345` to indicate that
   a test addresses the bugbug A bug is an error or unexpected result. Performance
   improvements, code optimization, and are considered enhancements, not defects.
   After feature freeze, only bugs are dealt with, with regressions (adverse changes
   from the previous version) being the highest priority. described in ticketticket
   Created for both bug reports and feature development on the bug tracker. [#12345](https://core.trac.wordpress.org/ticket/12345).
   Internally, `@ticket` annotations are translated to `@group`, so that you can
   limit test runs to those associated with a specific ticket: `$ phpunit --group
   12345`.
 * `@expectedDeprecated` – Custom to WordPress. Indicates that a `_deprecated_*()`
   notice is expected to be thrown by the specified function/method/class. Without
   this annotation, tests that trigger a deprecation notice will fail; similarly,
   if you include this annotatation but the test does not trigger a deprecation 
   notice, the test will fail. For example, tests for the deprecated `like_escape()`
   contain the annotation `@expectedDeprecated like_escape`.
 * `@expectedIncorrectUsage` – Similar to `@expectedDeprecated`, but for `_doing_it_wrong()`
   notices.

## 󠀁[Naming and Organization](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#naming-and-organization)󠁿

The WordPress team strives to make tests easy to find, easy to maintain, and easy
to run in isolation. As such, we have a number of guidelines for organizing and 
naming tests.

All PHPUnit tests are located in the `/tests/phpunit/tests/` directory. Paths given
below are relative to this root.

### 󠀁[Test Classes](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#test-classes)󠁿

Tests are organized into classes. Group tests into a class when they test different
aspects of the same piece of functionality. It’s especially convenient to put tests
together in a class when they can share a common `set_up()` or `set_up_before_class()`
routine. As a rule, a single test class should not contain tests for more than one
function/method.

Each test class should be in its own file. Test files are sorted into folder based
on shared functionality, which generally matches the primary `@group` annotation
for those tests. Test files should be named using camelCase.

Test class names should reflect the filepath, with underscores replacing directory
separators and TitleCase replacing camelCase. Thus, the class `Tests_Comment_GetCommentClass()`,
which contains tests for the `get_comment_class()` function, is located in `tests/
comment/getCommentClass.php`.

### 󠀁[Test Methods](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#test-methods)󠁿

Method names in a test class must begin with `test_`. Methods that do not begin 
with `test_` will not be run by PHPUnit; filterFilter Filters are one of the two
types of Hooks [https://codex.wordpress.org/Plugin_API/Hooks](https://codex.wordpress.org/Plugin_API/Hooks).
They provide a way for functions to modify data of other functions. They are the
counterpart to Actions. Unlike Actions, filters are meant to work in an isolated
manner, and should never have side effects such as affecting global variables and
output. callbacks or other utility methods should not have this prefix. Test method
names should be written in snake_case.

The test name should be as descriptive as possible. For example, `Tests_Comment_GetCommentClass::
test_should_accept_comment_id()` tests whether `get_comment_class()` accepts a comment
ID. Test names that describe the desired outcome of the test, ideally containing
the word ‘should’, make debugging far easier; a good test name might make it unnecessary
to look at the test source when a failure is spotted during a test run.

## 󠀁[Advanced Topics](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#advanced-topics)󠁿

### 󠀁[Slow Fixtures](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#slow-fixtures)󠁿

Sometimes, all tests in a class can use the same database fixtures. Generating these
fixtures inside of `set_up()` will cause them to be recreated for each test, which
can dramatically decrease test performance. In these cases, it’s possible to create
fixtures once, before any tests in the class have run, using `wpSetUpBeforeClass()`:

    ```notranslate
    class Tests_Comment_Stuff {
    	protected static $comment_post_id;

    	public static function wpSetUpBeforeClass( $factory ) {
    		self::$comment_post_id = $factory->post->create();
    	}
    }
    ```

Similarly, `wpTearDownAfterClass()` can be used for cleanup after all of a class’
tests have been run (though note that this is generally unnecessary, as the test
suite tries to clean up all shared fixtures automatically).

Some notes about shared fixtures:

 * `wpSetUpBeforeClass()` and `wpTearDownAfterClass()` must be declared as static
   and called statically.
 * Because the methods are static, the way that the data is stored for use in the
   test methods must also be static: `self::$foo` rather than `$this->foo`.
 * Do not call `self::factory()` in `wpSetUpBeforeClass()`, as it will break the
   uniqueness iterator; always use the `$factory` object passed to the method.

### 󠀁[Repetitive Tests](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#repetitive-tests)󠁿

Whenever you have the inclination to copy and paste the code of a test method to
test the same WordPress functionality with only slightly different arguments, please
consider using a data provider instead.

A [data provider](https://docs.phpunit.de/en/9.6/writing-tests-for-phpunit.html#data-providers)
is a secondary function which is linked to a test using a `@dataProvider` annotation
in the docblock of the test method and is generally named after the test, replacing
the `test` prefix in the method name with `data`.

This second function must return an array of arrays, where each entry in this array
is called a _data set_ and passed to the test function as input parameters.

It is highly recommended to use [named data sets](https://docs.phpunit.de/en/9.6/writing-tests-for-phpunit.html#writing-tests-for-phpunit-data-providers-examples-datatest1-php)
in a data provider.

### 󠀁[One-off Functions for Hooks](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#one-off-functions-for-hooks)󠁿

If your test needs a one-off callback function to hook into an action/filter, please
feel free to use a [closure](https://www.php.net/functions.anonymous) (anonymous
function).

And if your closure does not use the `$this` variable, please declare the closure
as `static` for optimal performance.

Using closures as hook callbacks _in CoreCore Core is the set of software required
to run WordPress. The Core Development Team builds WordPress./plugins/themes_ is**
not** recommended, as anonymous functions do not allow for unhooking the callback
from the hook. However, this is not a problem in the test suite, as the whole stack
of registered actions and filters will be reset after each test via the shared `
tear_down()` method.

## 󠀁[Technical Overview](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#technical-overview)󠁿

For the curious, here’s a quick overview of how PHPUnit is leveraged to work with
an application like WordPress.

### 󠀁[The WordPress Installation and Bootstrap](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#the-wordpress-installation-and-bootstrap)󠁿

When `phpunit` is invoked, the test suite runs a script that sets up a default installation
of WordPress, with a configuration similar to what you get with the GUI install.
Before any tests are run, the following steps take place:

 * WordPress is bootstrapped (by including `wp-settings.php`). This means that all
   tests run _after_ the entire WP bootstrap (through `wp_loaded`).
 * All default content is deleted. This includes sample posts and pages, but does
   _not_ include the default user or the ‘Uncategorized’ categoryCategory The ‘category’
   taxonomy lets you group posts / content together that share a common bond. Categories
   are pre-defined and broad ranging..

### 󠀁[Globals](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#globals)󠁿

The WP globals that reflect current page state, such as `$wp` and `$wp_query`, are
reset to a default state after each test is run. Similarly, post-related globals
like `$post` and `$more` are set to `null` after each test. The test suite also 
resets runtime-registered object types to their defaults; this means that custom
post types, taxonomies, etc must be reregistered for every test. Last but not least,
all actions and filters are reset to their original state after each test as well,
so it is not necessary to manually remove hooks that have been added in a test.

Modifications to other globals should be managed carefully by the tests themselves.
A simple convention to do so is to store the original global in a local variable
and reset it back to that value after the test logic has been run. It is important
that such resets should happen before the actual assertion is made, so that subsequent
test results are not polluted by one possible failure.

### 󠀁[Database](https://make.wordpress.org/core/handbook/testing/automated-testing/writing-phpunit-tests/?output_format=md#database)󠁿

WordPress keeps both data (posts, users) and state (options) in the database. And
the structure of WordPress is such that it’s almost impossible to mock fixtures 
and settings without actually using a database. As such, the test suite _does_ use
a MySQLMySQL MySQL is a relational database management system. A database is a structured
collection of data where content, configuration and other options are stored. [https://www.mysql.com](https://www.mysql.com/)
database for setting up the WP application and for storing fixtures and other data.

It’s important to distinguish between persistent and non-persistent database content
in the test suite. When `phpunit` is invoked, the test suite wipes the test database
clean and performs a clean installation. This data – such as the default content
of `wp_options` – is persistent through the tests.

Database modifications made during test, on the other hand, are _not_ persistent.
Before each test, the suite opens a MySQL transaction (`START TRANSACTION`) with`
autocommit` disabled, and at the end of each test the transaction is rolled back(`
ROLLBACK`). This means that database operations performed from within a test, such
as the creation of test fixtures, are discarded after each test. For more information
on transactions, see [the official MySQL documentation](https://dev.mysql.com/doc/refman/5.7/en/commit.html),
and especially the section on [statements that trigger commits](https://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html).

First published

August 30, 2017

Last updated

May 9, 2024

[  Previous: PHP: PHPUnit](https://make.wordpress.org/core/handbook/testing/automated-testing/phpunit/)

[  Next: Beta Testing](https://make.wordpress.org/core/handbook/testing/beta-testing/)