Back to Blog
Lesson 42 of the Intermediate WordPress Plugins: REST API & React Admin course
WordPressJune 26, 20263 min read

Unit Testing API Endpoints in WordPress: A Practical Guide

Learn how to use PHPUnit to test your WordPress REST API endpoints. We cover setting up WP_UnitTestCase, mocking requests, and verifying secure responses.

WordPressPHPUnitREST APITestingUnit TestingPlugin Developmentphpplugin-development

Previously in this course, we explored Implementing Activity Logging: Auditing REST API Changes in WordPress to track data mutations. Now, we shift our focus from runtime logging to development-time verification by learning how to perform unit testing on your API endpoints.

If you have already followed the Unit Testing Foundations: Ensuring WordPress Plugin Stability, you are likely familiar with the standard testing scaffold. Today, we apply those principles to the REST API, ensuring our routes remain reliable as the codebase grows.

Setting Up WP_UnitTestCase for the REST API

To test the REST API, you cannot simply call your callback functions directly. You must simulate the full routing lifecycle. The WP_REST_Request class and the WP_REST_Server are the core components here.

First, ensure your test suite inherits from WP_UnitTestCase. This base class provides the necessary hooks to reset the database and the global state between tests, which is critical for consistent API results.

PHP
class Test_Knowledge_Base_API extends WP_UnitTestCase {
    protected $server;

    public function setUp(): void {
        parent::setUp();
        #6A9955">// Access the global REST server
        global $wp_rest_server;
        $this->server = $wp_rest_server = new WP_REST_Server();
        do_action('rest_api_init');
    }
}

By manually instantiating WP_REST_Server and triggering rest_api_init, we ensure that our plugin's routes are registered before any test runs.

Testing API Responses

When testing an endpoint—such as the one we built in Creating POST Endpoints for Data Submission in WordPress REST API—we need to verify both the status code and the structure of the JSON response.

Here is how you dispatch a request programmatically and assert the outcome:

PHP
public function test_get_kb_items_returns_data() {
    #6A9955">// 1. Create a dummy post for the test
    $post_id = $this->factory->post->create(['post_type' => 'kb_item']);

    #6A9955">// 2. Prepare the request
    $request = new WP_REST_Request('GET', '/kb/v1/items');

    #6A9955">// 3. Dispatch the request through the server
    $response = $this->server->dispatch($request);

    #6A9955">// 4. Run assertions
    $this->assertEquals(200, $response->get_status());
    $data = $response->get_data();
    $this->assertIsArray($data);
    $this->assertEquals($post_id, $data[0]['id']);
}

Mocking Requests and Permissions

One of the most powerful features of WP_UnitTestCase is the ability to spoof the current user. Since most endpoints rely on permission_callback, you need to test both authorized and unauthorized states.

Use wp_set_current_user() to simulate different user levels:

PHP
public function test_unauthorized_user_cannot_create_item() {
    #6A9955">// Set current user to a subscriber(lacks 'edit_posts' capability)
    $user_id = $this->factory->user->create(['role' => 'subscriber']);
    wp_set_current_user($user_id);

    $request = new WP_REST_Request('POST', '/kb/v1/items');
    $request->set_param('title', 'Test Title');

    $response = $this->server->dispatch($request);

    #6A9955">// Assert that the API returns a 403 Forbidden
    $this->assertEquals(403, $response->get_status());
}

Hands-on Exercise

Using the Knowledge Base plugin project:

  1. Identify a GET endpoint you created earlier.
  2. Create a new test file in your tests/ directory if you haven't already.
  3. Write a test that creates a piece of content, calls your endpoint, and asserts that the returned JSON contains the expected fields.
  4. Add a second test case that verifies a 401 or 403 response when no user is logged in.

Common Pitfalls

  • Forgetting rest_api_init: If your tests fail with a "No route was found" error, it usually means your plugin's register_rest_route calls haven't been triggered in the test environment. Ensure do_action('rest_api_init') is called in setUp().
  • Persistent State: Always use the built-in factory methods ($this->factory->post->create()) to generate data. These methods ensure data is cleaned up automatically, preventing test pollution.
  • Ignoring Nonces: Remember that while WP_REST_Request bypasses some browser-based security checks, your code might still check for nonces. You may need to inject a valid nonce into the request object using $request->set_header('X-WP-Nonce', wp_create_nonce('wp_rest')).

By incorporating these testing patterns, you ensure that your API remains a stable contract for your React frontend. Testing your endpoints is the final gatekeeper for code quality in a decoupled architecture.

Up next: We will move to the client side and learn how to perform Unit Testing for React Components, ensuring our UI logic is as robust as our backend.

Similar Posts