Adding automated unit tests to a WordPress plugin

A client running a high-traffic membership site once called me at 2:00 AM because their renewals were failing. They had just pushed a “minor” update to their custom payment plugin, and nothing looked wrong from the front end. A typo in one filter was canceling 15% of renewals, which cost them thousands in a single night. The developer who shipped it was not careless. He tested by hand: click through the checkout, see the “Thank You” page, call it done.

That night changed how I work. Without automated unit tests in your WordPress development, every deploy comes down to hoping the paths you did not click still behave. Manual verification holds up right until the release where it doesn’t, and the hours you save by skipping tests come back with interest when production breaks on a Friday afternoon.

Where manual testing breaks down

My first answer was to be “more careful,” which in practice meant a checklist of everything to click before a release. That lasted about a week. We shipped one more feature and the checklist turned into a book nobody finished reading. People are bad at repetitive checks, especially late in a release cycle, and a test suite is not. That is the whole argument for having one.

Setup starts with the WP-CLI scaffold command, which writes out the environment files for you. The full technical detail lives in the official documentation on developer.wordpress.org, but one command gets you the skeleton.

wp scaffold plugin-tests bbioon-custom-plugin --ci=github

Writing tests that catch real bugs

Once the files are in place, drop the idea of covering every line. Test the logic that would hurt you if it changed quietly. If you register a Custom Post Type (CPT), assert that it exists and that it is public, because a CPT that stops being public takes your SEO down with it.

A test class usually extends WP_UnitTestCase, which hands you the factory: a helper for creating posts, users and terms in a clean, sandboxed database. It saves a lot of mocking by hand.

<?php
/**
 * Testing the Bbioon Booking Engine
 */
class Test_Bbioon_Booking_CPT extends WP_UnitTestCase {

	public function setUp(): void {
		parent::setUp();
		// Ensure our CPT is loaded for every test
		bbioon_register_booking_cpt();
	}

	public function bbioon_test_booking_registration() {
		$post_type_obj = get_post_type_object( 'bbioon_booking' );

		$this->assertNotNull( $post_type_obj, 'Post type must be registered' );
		$this->assertTrue( $post_type_obj->public, 'Post type must be public' );
	}

	public function bbioon_test_can_save_metadata() {
		$post_id = self::factory()->post->create( array(
			'post_type' => 'bbioon_booking',
			'post_title' => 'Client Consultation'
		) );

		update_post_meta( $post_id, '_bbioon_status', 'confirmed' );
		
		$this->assertEquals( 'confirmed', get_post_meta( $post_id, '_bbioon_status', true ) );
	}
}

What this buys you

Regression prevention, mostly. Add a feature six months from now, run composer test, and you know in seconds whether the booking logic still works, rather than hearing about it in a 2:00 AM phone call. If you charge clients for custom work, that kind of stability is part of what they are paying for.

Test setups get complicated once WooCommerce dependencies or heavier database queries are in play. If you would rather not spend your week untangling someone else’s plugin, drop my team a line. We have probably seen your version of it before.

Start small with automated unit tests. Cover the core functions first, then widen the suite as the plugin grows.

author avatar
Ahmad Wael
I'm a WordPress and WooCommerce developer with 15+ years of experience building custom e-commerce solutions and plugins. I specialize in PHP development, following WordPress coding standards to deliver clean, maintainable code. Currently, I'm exploring AI and e-commerce by building multi-agent systems and SaaS products that integrate technologies like Google Gemini API with WordPress platforms, approaching every project with a commitment to performance, security, and exceptional user experience.