Skip to content

Test the Application

Configuration-dependent tests need different setup depending on the boundary under test. Construct a fresh container when testing one provider. Start a new PHP process when the complete WordPress application must read different environment values during bootstrap.

Focused provider tests should pass configuration values directly to a new ArrayConfiguration. Create a new container for each scenario so registered bindings and resolved singletons cannot retain values from another test:

<?php declare(strict_types=1);

namespace Plugin\Tests\Feature\Catalog;

use PHPUnit\Framework\TestCase;
use Plugin\Catalog\Catalog_Provider;
use Plugin\Catalog\Catalog_Synchronizer;
use StellarWP\Foundation\Container\Configuration\ArrayConfiguration;
use StellarWP\Foundation\Container\ContainerFactory;

final class Catalog_Provider_Test extends TestCase {

	public function test_it_disables_catalog_synchronization(): void {
		$config = new ArrayConfiguration( [
			'catalog' => [
				'sync_enabled' => false,
			],
		] );
		$container = ( new ContainerFactory() )->create( $config );
		$container->register( Catalog_Provider::class );

		$synchronizer = $container->get( Catalog_Synchronizer::class );

		$this->assertFalse( $synchronizer->is_enabled() );
	}
}

This approach tests provider behavior without relying on the application’s static App singleton or changing process-level environment values. Use a WordPress-loaded test suite when the provider itself registers hooks or otherwise requires WordPress APIs.

Tests that exercise the complete application need a new PHP process. wp-browser’s WPLoader loads WordPress and active plugins before PHPUnit runs a test class’s setup hooks, so changing $_ENV in an ordinary setUp() method does not reconfigure an App singleton that already exists.

Enable wp-browser’s isolation extension in the root codeception.dist.yml. The extension starts another Codeception process for isolated tests so WPLoader can boot WordPress and the application from a clean PHP process:

extensions:
  enabled:
    - lucatume\WPBrowser\Extension\IsolationSupport

Set the environment in the standard setUpBeforeClass() hook and mark the class with RunTestsInSeparateProcesses. Although WPLoader has already booted the application in the outer test process, wp-browser launches the isolated Codeception process when the test method begins. The child inherits the environment before its own WPLoader initializes, so it constructs a new application with the configured value.

Synchronize the process environment with $_ENV and $_SERVER so Symfony Process passes a newly introduced variable to the child:

<?php declare(strict_types=1);

namespace Plugin\Tests\WPUnit\Catalog;

use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
use Plugin\Catalog\Catalog_Synchronizer;
use Plugin\Tests\WPUnitSupport\WPTestCase;

use function Plugin\plugin;

#[RunTestsInSeparateProcesses]
final class Catalog_Application_Test extends WPTestCase {

	private const string ENV_SYNC_ENABLED = 'CATALOG_SYNC_ENABLED';

	private static string|false $original_sync_enabled;

	public static function setUpBeforeClass(): void {
		self::$original_sync_enabled = getenv( self::ENV_SYNC_ENABLED );
		self::set_sync_enabled_environment( 'true' );

		parent::setUpBeforeClass();
	}

	public static function tearDownAfterClass(): void {
		if ( self::$original_sync_enabled === false ) {
			putenv( self::ENV_SYNC_ENABLED );
			unset( $_ENV[ self::ENV_SYNC_ENABLED ], $_SERVER[ self::ENV_SYNC_ENABLED ] );
		} else {
			self::set_sync_enabled_environment( self::$original_sync_enabled );
		}

		parent::tearDownAfterClass();
	}

	public function test_it_boots_with_catalog_synchronization_enabled(): void {
		$synchronizer = plugin()->container()->get( Catalog_Synchronizer::class );

		$this->assertTrue( $synchronizer->is_enabled() );
	}

	private static function set_sync_enabled_environment( string $value ): void {
		putenv( self::ENV_SYNC_ENABLED . '=' . $value );
		$_ENV[ self::ENV_SYNC_ENABLED ]    = $value;
		$_SERVER[ self::ENV_SYNC_ENABLED ] = $value;
	}
}

Use one isolated test class for each application configuration. The underscored _setUpBeforeClass() hook remains available as a Codeception compatibility API, but new tests should use PHPUnit’s standard setUpBeforeClass() method.

Explore the Container component and the other focused Foundation packages.