Testing & Test Database Setup
Overview
Testing is a first-class citizen in the ValPress ecosystem. Built upon the robust Laravel testing suite, ValPress provides a comprehensive environment for unit, feature, and integration testing. Whether you are developing a core feature, a custom plugin, or a specialized theme, the testing framework ensures that your code is reliable, performant, and backward-compatible.
Why It Matters
A complex CMS like ValPress, with its extensive hook system and dynamic plugin architecture, requires rigorous testing to prevent regressions.
- Stability: Ensures that core updates do not break third-party extensions.
- Confidence: Allows developers to refactor code with the certainty that existing functionality remains intact.
- Interoperability: Verifies that multiple plugins and themes can coexist without conflict.
- Documentation: Tests serve as living documentation, demonstrating how APIs are intended to be used.
How It Works
ValPress leverages PHPUnit and Laravel's artisan test runner. When running tests, the application boots in the testing environment, which uses a
dedicated database and configuration.
The Testing Lifecycle
- Environment Boot: The
phpunit.xmlfile sets specific environment variables (e.g.,APP_ENV=testing,DB_CONNECTION=pgsql). - Configuration Isolation: Caches are cleared, and service providers are registered in a test-safe manner.
- Database Preparation: The test database is migrated and seeded (optionally using the
RefreshDatabasetrait). - Plugin/Theme Discovery: ValPress automatically discovers and includes tests located within plugin and theme directories thanks to specialized PSR-4
mappings in
composer.json.
Usage
1. PHPUnit Configuration
The phpunit.xml file in the root directory defines the default testing environment. ValPress ships with a pre-configured PostgreSQL setup:
<!-- Default DB settings in phpunit.xml -->
<env name="DB_CONNECTION" value="pgsql"/>
<env name="DB_HOST" value="127.0.0.1"/>
<env name="DB_PORT" value="5454"/>
<env name="DB_DATABASE" value="valpress_tests_db"/>
<env name="DB_USERNAME" value="postgres"/>
<env name="DB_PASSWORD" value="postgres"/>
To override these locally without modifying the shared phpunit.xml, copy .env.testing.example to .env.testing.
Always run tests via:
composer test
# or
php artisan test
Never run phpunit --no-configuration or point DB_DATABASE in .env at a test run — RefreshDatabase executes migrate:fresh and will erase all data in the connected database.
The Update Center core verify pipeline also requires a dedicated test database configured under Settings → Test Database. Use a separate database name from production. See Updates & Maintenance.
2. Creating the Test Database
Before running tests, you must ensure the test database exists.
PostgreSQL (Default)
Create the database and user as specified in your configuration:
# Example using psql
psql -U postgres -c "CREATE DATABASE valpress_tests_db;"
MySQL/MariaDB
If you prefer MySQL, update your DB_CONNECTION and create the database:
mysql -u root -e "CREATE DATABASE valpress_tests_db;"
SQLite (Recommended for Speed)
SQLite is ideal for fast unit tests. You can use an in-memory database or a file:
# In-memory (fastest)
DB_CONNECTION=sqlite
DB_DATABASE=:memory:
# File-based
DB_CONNECTION=sqlite
DB_DATABASE=database/database.sqlite
Note: Ensure touch database/database.sqlite is run if using file-based SQLite.
3. Preparing the Database Schema
Ensure your test database is up to date with the latest migrations:
php artisan migrate --database=testing
4. Running Tests
ValPress provides several ways to execute your test suite.
Running All Tests
# Using the composer script (clears config automatically)
composer test
# Using artisan directly
php artisan test
Running Specific Tests
# Run a specific file
php artisan test tests/Feature/PostsControllerTest.php
# Filter by test name
php artisan test --filter "test_can_create_post"
Code Examples
A Standard Feature Test
This example demonstrates testing a core post creation endpoint using the RefreshDatabase trait.
namespace Tests\Feature;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class PostCreationTest extends TestCase
{
use RefreshDatabase;
/** @test */
public function an_authorized_user_can_create_a_post()
{
// 1. Arrange: Authenticate a user
$user = User::factory()->create(['role' => 'admin']);
$this->actingAs($user);
// 2. Act: Submit a post request
$response = $this->post('/admin/posts', [
'title' => 'My Test Post',
'content' => 'Content of the test post.',
'status' => 'publish',
]);
// 3. Assert: Verify the post exists in the database
$response->assertStatus(302);
$this->assertDatabaseHas('posts', [
'title' => 'My Test Post'
]);
}
}
Testing a Plugin Hook
Testing how a plugin interacts with ValPress hooks:
namespace Plugins\HelloWorld\Tests;
use Tests\TestCase;
class HookTest extends TestCase
{
/** @test */
public function hello_world_filter_modifies_content()
{
$originalContent = "Hello";
// ValPress uses standard apply_filters
$filteredContent = apply_filters('the_content', $originalContent);
$this->assertStringContainsString('World', $filteredContent);
}
}
Advanced Usage
Testing Plugins and Themes
ValPress supports autoload-dev for plugins and themes. Place your tests in:
public/plugins/{plugin-slug}/tests/public/themes/{theme-slug}/tests/
These namespaces are automatically mapped to Plugins\Tests\ and Themes\Tests\.
Mocking External Services
Always mock external APIs or mail services to ensure tests remain fast and deterministic.
public function test_external_api_call()
{
Http::fake([
'api.valpress.net/*' => Http::response(['status' => 'ok'], 200),
]);
// ... perform action that calls API
}
Best Practices
- Use
RefreshDatabase: Always use this trait for tests that interact with the database to ensure a clean state for every test method. - Prefer SQLite for Unit Tests: Unless you are testing database-specific features (like PostgreSQL JSONB), SQLite is significantly faster.
- Keep Tests Isolated: One test should not depend on the results of another.
- Mock Services: Use
Mail::fake(),Event::fake(), andHttp::fake()to prevent side effects. - Document Logic via Tests: Use descriptive test names like
test_cannot_delete_published_post_without_permission.
Common Mistakes
- Running Tests on Production DB: Never use
phpunit --no-configuration. ValPress aborts tests whenAPP_ENVis nottestingor whenDB_DATABASEdoes not includetest. Always usecomposer testorphp artisan testwith a dedicated test database configured inphpunit.xml/.env.testing. Never point the Update Center test database at production. - Hardcoding IDs: Avoid hardcoding database IDs; use factories to generate related models dynamically.
- Ignoring Cache: Tests can sometimes fail because of stale configuration caches. Use
php artisan config:clearor thecomposer testcommand. - Missing Autoloading: Ensure your plugin/theme test directories follow the PSR-4 structure defined in
composer.jsonor they won't be discovered.
Summary
Testing in ValPress is designed to be seamless and powerful. By leveraging Laravel's native tools and extending them to the plugin architecture, ValPress ensures that developers can build high-quality, stable extensions with ease. Setting up a dedicated test database and following best practices will result in a faster, more reliable development workflow.