# Testing > Generated: 2026-04-26 ## Framework - **PHPUnit 10.5+** (`phpunit/phpunit` in `composer.json` dev) - Config: `phpunit.xml` at project root - Bootstrap: `tests/bootstrap.php` ## Structure ``` tests/ ├── bootstrap.php Test bootstrap (PSR-4 autoload for Domain\) ├── stubs/ │ ├── CacheHandler.php In-memory stub (replaces file-based cache) │ └── S.php Helper facade stub └── Unit/ └── Domain/ ├── Languages/LanguagesRepositoryTest.php ├── Settings/SettingsRepositoryTest.php └── User/UserRepositoryTest.php ``` ## Bootstrap Setup `tests/bootstrap.php`: - Loads Medoo ORM (`libraries/medoo/medoo.php`) - Loads stubs **before** autoloader (to override `Shared\Cache\CacheHandler`) - Registers PSR-4 autoloader for `Domain\` namespace only **Critical**: Stubs must be loaded before autoloader. CacheHandler stub provides `reset()` method for test isolation. ## Test Pattern All tests follow **AAA (Arrange-Act-Assert)** with Medoo mocked: ```php namespace Tests\Unit\Domain\Languages; use Domain\Languages\LanguagesRepository; use PHPUnit\Framework\TestCase; class LanguagesRepositoryTest extends TestCase { private function mockDb(): object { return $this->createMock(\medoo::class); } protected function setUp(): void { \Shared\Cache\CacheHandler::reset(); // clear in-memory cache } public function testLanguagesListReturnsArray(): void { $db = $this->mockDb(); $db->method('select')->willReturn([['id' => 'pl', 'name' => 'Polski']]); $repo = new LanguagesRepository($db); $result = $repo->languagesList(); $this->assertSame([['id' => 'pl', 'name' => 'Polski']], $result); } public function testLanguagesListReturnsEmptyWhenNull(): void { $db = $this->mockDb(); $db->method('select')->willReturn(null); $this->assertSame([], (new LanguagesRepository($db))->languagesList()); } public function testActiveLanguagesQueriesDbAndCaches(): void { $expected = [['id' => 'pl', 'name' => 'Polski', 'domain' => null]]; $db = $this->mockDb(); $db->expects($this->once())->method('select')->willReturn($expected); $repo = new LanguagesRepository($db); $this->assertSame($expected, $repo->activeLanguages()); $this->assertSame($expected, $repo->activeLanguages()); // 2nd call hits cache } } ``` ## Stubs ### `tests/stubs/CacheHandler.php` In-memory replacement for `Shared\Cache\CacheHandler`: - `static::$store` — array key-value store - `reset()` — clear all stored values (call in `setUp()`) - `fetch($key)` — return stored value or `false` - `store($key, $value, $ttl)` — store value (TTL ignored) - `delete($key)` — remove value ### `tests/stubs/S.php` Stub for the `\S` global helper facade — prevents tests from hitting real filesystem/session code. ## Coverage Currently tested: **Domain layer only** - `Domain\Languages\LanguagesRepository` ✓ - `Domain\Settings\SettingsRepository` ✓ - `Domain\User\UserRepository` ✓ - All other Domain repositories: **no tests yet** Not tested: - `admin\controls\*` — static controllers - `admin\factory\*` — deprecated wrappers - `front\*` — frontend layer - `Shared\*` — utilities - AJAX handlers ## Running Tests ```bash composer test # or ./vendor/bin/phpunit ``` ## Adding Tests for New Repositories When adding a new `Domain\{Entity}\{Entity}Repository`: 1. Create `tests/Unit/Domain/{Entity}/{Entity}RepositoryTest.php` 2. Call `\Shared\Cache\CacheHandler::reset()` in `setUp()` if the repo uses caching 3. Mock `\medoo` via `$this->createMock(\medoo::class)` 4. Test: null-to-empty-array coercion, cache hit (expects `once()`), write returns expected type