Testy
Projekt používá Pest PHP pro testování. Testy jsou organizovány do čtyř kategorií: Unit, Integration, Feature a Architecture. Všechny jsou uloženy v adresáři /tests.
Spuštění testů
Všechny testy
./pest
Konkrétní kategorii testů
./pest tests/Unit
./pest tests/Integration
./pest tests/Feature
./pest tests/Architecture
Filtrování podle názvu
./pest --filter CacheTest
./pest --filter "save item"
./pest --filter Cache tests/Unit
Konkrétní soubor
./pest tests/Unit/Core/Cache/CacheTest.php
Testy se skupinami
./pest --group architecture
./pest --group database
./pest --group cache
Paralelní běh (zrychlení)
./pest --parallel
Struktura testů
Testy jsou organizovány podle skutečné vrstvy kódu, ne podle funkce:
tests/
├── Unit/ # Jednotlivé komponenty bez závislostí
│ ├── Core/ # core/ kód
│ │ ├── Array/
│ │ ├── Cache/
│ │ │ └── CacheTest.php
│ │ ├── FileSystem/
│ │ ├── Http/
│ │ ├── Validation/
│ │ └── ... (35+ test souborů)
│ │
│ ├── App/ # app/* mimo Modules
│ ├── Console/ # Parser a CLI helpery
│ │
│ └── Modules/ # app/Modules/ bez DB (zatím prázdné)
│
├── Integration/ # Skutečné závislosti (DB, soubory)
│ ├── Core/ # core/ s databází
│ │ ├── Cache/
│ │ │ └── CacheFileTest.php
│ │ ├── Database/
│ │ │ ├── DBTest.php
│ │ │ ├── DBSetTest.php
│ │ │ └── DBSpecialCasesTest.php
│ │ └── Session/
│ │ └── SessionTest.php
│ │
│ ├── App/ # app/* s DB (TBD)
│ │
│ └── Modules/ # app/Modules/ s DB (business logic)
│ └── I18n/
│ └── I18nFrontendServiceTest.php
│
├── Feature/ # End-to-end nebo route-level scénáře
│
├── Architecture/ # Globální architekturní pravidla
│ ├── CubeSystemArchTest.php
│ ├── MiddlewareAndRoutingArchTest.php
│ ├── TemplateLayerArchTest.php
│ └── README.md
│
├── Support/ # Test helpery a fixtures
│ ├── Architecture/
│ │ └── ArchitectureHelper.php
│ └── DatabaseSetup.php
│
└── Pest.php # Globální Pest konfigurace
Vrstvení — Co kam patří
- Unit/Core/... —
core/kód bez DB, bez souboru - Unit/App/... —
app/*mimo modules, bez DB - Unit/Console/... — parser a CLI chování
- Unit/Modules/... —
app/Modules/*bez DB přístupu - Integration/Core/... —
core/s DB, Session, File cache - Integration/Modules/... —
app/Modules/*s DB přístupem (Service vrstva) - Feature/... — scénáře přes route, request/response nebo vyšší vrstvu aplikace
Psaní testů
Jednoduchý Unit test
<?php
declare(strict_types=1);
use Core\Cache\Cache;
test('save item with valid data', function () {
$itemName = 'test_item';
$data = ['key' => 'value'];
Cache::set($itemName, $data, 60);
expect(Cache::get($itemName))->toEqual($data);
});
test('save item with empty array', function () {
Cache::set('test', [], 60);
expect(Cache::get('test'))->toEqual([]);
});
Test se skupinou a tagy
<?php
test('SQL is parameterized', function () {
// test code
})
->group('architecture', 'database');
Integration test s databází
<?php
declare(strict_types=1);
use Core\Database\DB;
// Databáze se automaticky inicializuje (viz tests/Pest.php)
// Transakce se vrací po testu (rollback)
test('insert user', function () {
DB::beginTransaction();
DB::query("INSERT INTO temp_users (name) VALUES (?)", ['Alice']);
$user = DB::row("SELECT * FROM temp_users WHERE name = ?", ['Alice']);
expect($user)->not->toBeNull();
expect($user->name)->toEqual('Alice');
DB::rollback();
});
Test s Before/After hooks
<?php
beforeAll(function () {
// Spustí se jednou na začátku všech testů v souboru
Cache::clear();
});
afterAll(function () {
// Spustí se jednou na konci všech testů v souboru
Cache::clear();
});
test('uses clean cache', function () {
// Cache je čistá
});
Expect Assertions (Pest)
Pest používá fluent syntaxi přes expect():
// Základní kontroly
expect($result)->toBe(true);
expect($result)->toBeTrue();
expect($result)->toBeFalse();
expect($result)->toBeNull();
// Porovnání
expect($value)->toEqual(5);
expect($value)->toBe(5); // Striktnější (===)
expect($value)->toNotEqual(5);
// Typy
expect($value)->toBeArray();
expect($value)->toBeString();
expect($value)->toBeInt();
expect($value)->toBeInstanceOf(stdClass::class);
// Stringy
expect($text)->toContain('substring');
expect($text)->toMatch('/pattern/');
expect($text)->toStartWith('prefix');
expect($text)->toEndWith('suffix');
// Kolekce
expect($array)->toHaveCount(3);
expect($array)->toHaveKey('key');
expect($array)->toContainEqual('value');
// Řetězování
expect($result)
->toBeArray()
->toHaveCount(3)
->toHaveKey('status')
->and($result['status'])->toEqual('ok');
Chyby a výjimky
// Kontrola vyhozené výjimky
expect(function () {
throw new Exception('Error message');
})->toThrow(Exception::class);
// S konkrétní zprávou
expect(function () {
throw new Exception('Custom error');
})->toThrow(Exception::class, 'Custom error');
// V PHPUnit stylu (legacy)
$this->expectException(Exception::class);
$this->expectExceptionMessage('message');
Fixture Data & Faker
Projektuje k dispozici knihovna Faker pro generování testovacích dat:
<?php
use Faker\Factory;
beforeEach(function () {
$faker = Factory::create('cs_CZ');
$this->user = [
'name' => $faker->name(),
'email' => $faker->email(),
'phone' => $faker->phoneNumber(),
'city' => $faker->city(),
];
});
test('creates user with faker data', function () {
expect($this->user['name'])->toBeString();
});
Pest Konfigurace
Konfigurace je v tests/Pest.php:
use Tests\Support\DatabaseSetup;
require_once __DIR__ . '/Support/Architecture/ArchitectureHelper.php';
// Automatická inicializace databáze pro Integration testy
uses()
->beforeEach(fn() => DatabaseSetup::init())
->in('Integration/Core/Database', 'Integration/Core/I18n', 'Integration/Modules');
Helpery jsou v tests/Support/:
- DatabaseSetup.php — Inicializace dočasných DB tabulek pro testy
- Architecture/ArchitectureHelper.php — Utility pro Architecture testy
Běžné Příklady
Test Cache komponenty
./pest --filter CacheTest
./pest tests/Unit/Core/Cache/CacheTest.php
Jen Unit testy
./pest tests/Unit
Jen Architecture testy
./pest tests/Architecture
S detailním výstupem
./pest -vv tests/Unit/Core/Cache/CacheTest.php
Best Practices
- Jeden test = jednu věc: Každý
test()by měl testovat jednu funkcionalitu - Jasné názvy:
test('save item with valid data')je lepší nežtest('save') - Arrange-Act-Assert: Příprava → Spuštění → Kontrola
- Čisté testy: Database/Cache se automaticky čistí mezi testy
- Soubory podle třídy:
I18nFrontendServiceTest.phptestujeI18nFrontendService, neServiceTest.php - Umístění podle vrstvy:
core/Foo/Bar.php→tests/Unit/Core/Foo/BarTest.php(nebo Integration)app/Modules/News/Service.php→tests/Unit/Modules/News/ServiceTest.php(nebo Integration)app/Console/Parser.php→tests/Unit/App/Console/ParserTest.php- Žádný suffix v názvu:
CacheFileTest.php(neCacheFileIntegrationTest.php— typ je v cestě)
Continuous Integration
Při commitu spustit testy:
./pest
Jen testy bez lintů:
./pest