Testing
Running Tests
# Run all tests
composer test
# Run with verbose output
vendor/bin/phpunit --verbose
# Run a specific test class
vendor/bin/phpunit tests/Unit/ModelCollectionTest.php
# Run a specific test method
vendor/bin/phpunit --filter test_pluck_extracts_key_from_objects
Test Setup
The package includes a tests/bootstrap.php that provides mock WordPress functions so you can test without a running WordPress installation.
Bootstrap
// tests/bootstrap.php
require_once dirname(__DIR__) . '/vendor/autoload.php';
// WordPress mocks are provided:
// sanitize_title(), wp_hash_password(), current_time(), absint(), esc_sql()
Writing Unit Tests for Your Models
Testing ModelCollection
The ModelCollection class has no external dependencies and can be tested directly:
<?php
declare(strict_types=1);
namespace Tests\Unit;
use PHPUnit\Framework\TestCase;
use WPZylos\Framework\Model\ModelCollection;
class ModelCollectionTest extends TestCase
{
public function test_pluck(): void
{
$items = [
(object) ['name' => 'Alice'],
(object) ['name' => 'Bob'],
];
$collection = new ModelCollection($items);
$this->assertSame(['Alice', 'Bob'], $collection->pluck('name'));
}
public function test_filter(): void
{
$collection = new ModelCollection([1, 2, 3, 4, 5]);
$evens = $collection->filter(fn($n) => $n % 2 === 0);
$this->assertSame([2, 4], $evens->all());
}
}
Testing HasAttributes
Create a concrete stub to test the trait in isolation:
<?php
declare(strict_types=1);
namespace Tests\Unit;
use PHPUnit\Framework\TestCase;
use WPZylos\Framework\Model\Concerns\HasAttributes;
class HasAttributesTest extends TestCase
{
private function makeStub(array $casts = []): object
{
return new class ($casts) {
use HasAttributes;
protected array $casts;
public function __construct(array $casts)
{
$this->casts = $casts;
}
public function set(string $key, mixed $value): void
{
$this->setAttribute($key, $value);
}
public function get(string $key): mixed
{
return $this->getAttribute($key);
}
};
}
public function test_integer_cast(): void
{
$stub = $this->makeStub(['age' => 'int']);
$stub->set('age', '25');
$this->assertSame(25, $stub->get('age'));
}
public function test_dirty_tracking(): void
{
$stub = $this->makeStub();
$stub->set('name', 'Original');
$stub->syncOriginal();
$stub->set('name', 'Changed');
$this->assertTrue($stub->isDirty('name'));
}
}
Testing Events
<?php
declare(strict_types=1);
namespace Tests\Unit;
use PHPUnit\Framework\TestCase;
use WPZylos\Framework\Model\Concerns\HasEvents;
class HasEventsTest extends TestCase
{
protected function setUp(): void
{
// Concrete class for testing
TestEventModel::flushEventListeners();
}
public function test_event_fires(): void
{
$fired = false;
TestEventModel::registerModelEvent('creating', function () use (&$fired) {
$fired = true;
});
$model = new TestEventModel();
// ... trigger event
$this->assertTrue($fired);
}
}
Testing with Mocked Database
For integration-level tests, you can mock the Connection and QueryBuilder:
<?php
declare(strict_types=1);
namespace Tests\Unit;
use PHPUnit\Framework\TestCase;
use WPZylos\Framework\Core\Contracts\ApplicationInterface;
use WPZylos\Framework\Model\Model;
class ModelIntegrationTest extends TestCase
{
private ApplicationInterface $app;
protected function setUp(): void
{
$this->app = $this->createMock(ApplicationInterface::class);
Model::setApplication($this->app);
}
protected function tearDown(): void
{
// Reset static state
$ref = new \ReflectionClass(Model::class);
$prop = $ref->getProperty('app');
$prop->setAccessible(true);
$prop->setValue(null, null);
}
public function test_get_application(): void
{
$this->assertSame($this->app, Model::getApplication());
}
}
Code Coverage
Generate coverage reports:
# HTML report
vendor/bin/phpunit --coverage-html coverage/
# Text summary
vendor/bin/phpunit --coverage-text
Static Analysis
# Run PHPStan
composer analyze
# Check code style
composer cs
# Fix code style
composer cs-fix
# Run all quality checks
composer qa