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.
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.
PHPclass 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:
PHPpublic 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:
PHPpublic 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:
- Identify a
GETendpoint you created earlier. - Create a new test file in your
tests/directory if you haven't already. - Write a test that creates a piece of content, calls your endpoint, and asserts that the returned JSON contains the expected fields.
- 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'sregister_rest_routecalls haven't been triggered in the test environment. Ensuredo_action('rest_api_init')is called insetUp(). - Persistent State: Always use the built-in
factorymethods ($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_Requestbypasses 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.
Work with me

Custom WordPress Plugin Development
Custom WordPress & WooCommerce plugins built to standard — by the developer behind a plugin with 5,000+ active installs and a SaaS with 10,000+ users.

Laravel REST API Development
Clean, secure, well-documented Laravel REST APIs — the backend engine for your app, mobile client, or SaaS. Built by an API specialist.