Unit тесты — IO7 Framework
Внимание
Данная статья документации написана нейросетью. Возможны некоторые расхождения и неточность информации!
Обзор
Unit тесты проверяют отдельные компоненты фреймворка в изоляции. IO7 включает готовые unit тесты для ключевых компонентов: авторизация, база данных, контейнер, логирование, профилирование.
Требования: PHP ^8.2, Illuminate (Laravel 13), PHPUnit 11
Структура
app/Testing/
├── Unit/
│ ├── Auth/
│ │ └── TokenManagerTest.php
│ ├── Database/
│ │ ├── DatabaseManagerTest.php
│ │ ├── ConnectionManagerTest.php
│ │ └── SqlConnectionTest.php
│ ├── Console/
│ │ └── CommandTest.php
│ ├── Profile/
│ │ └── PinbaManagerTest.php
│ ├── EventTest.php
│ ├── FormBuilderTest.php
│ └── ContainerTest.php
├── Feature/
│ └── ExampleTest.php
└── UserTest.php
Базовый класс TestCase
Базовый класс для тестов находится во фреймворке: IO\Testing\TestCase
namespace App\Testing\Unit;
use IO\Testing\TestCase;
class MyTest extends TestCase
{
public function testSomething(): void
{
$result = $this->getIodb()->search('users', []);
$this->assertNotEmpty($result['res']);
}
}
Методы TestCase
| Метод | Возврат | Описание |
|---|---|---|
getApp() | \IO\App | Получить экземпляр App |
getIodb() | \IO\Database\SqlConnection | Получить SqlConnection |
Запуск
# Все unit тесты
php vendor/bin/phpunit --testsuite Unit
# Один файл
php vendor/bin/phpunit app/Testing/Unit/Auth/TokenManagerTest.php
# Один метод
php vendor/bin/phpunit app/Testing/Unit/Auth/TokenManagerTest.php::testCreateAccessToken
Примеры тестов
TokenManagerTest
<?php
namespace Tests\Unit;
use Tests\TestCase;
use PHPUnit\Framework\Attributes\Test;
class TokenManagerTest extends TestCase
{
#[Test]
public function testCreateTokenManager(): void
{
$manager = \IO\Auth\TokenManager::init([
'secret_key' => 'test_secret_key_12345',
'access_ttl' => 3600,
'refresh_ttl' => 2592000,
]);
$this->assertInstanceOf(\IO\Auth\TokenManager::class, $manager);
}
#[Test]
public function testCreateAccessToken(): void
{
$manager = \IO\Auth\TokenManager::init([
'secret_key' => 'test_secret_key_12345',
'access_ttl' => 3600,
]);
$token = $manager->createAccessToken('user_123', ['read', 'write']);
$this->assertIsString($token);
$this->assertNotEmpty($token);
}
#[Test]
public function testValidateAccessToken(): void
{
$manager = \IO\Auth\TokenManager::init([
'secret_key' => 'test_secret_key_12345',
'access_ttl' => 3600,
]);
$token = $manager->createAccessToken('user_123', ['read']);
$payload = $manager->validateAccessToken($token);
$this->assertIsArray($payload);
$this->assertEquals('user_123', $payload['user_id']);
}
#[Test]
public function testValidateInvalidToken(): void
{
$manager = \IO\Auth\TokenManager::init([
'secret_key' => 'test_secret_key_12345',
]);
$payload = $manager->validateAccessToken('invalid_token');
$this->assertNull($payload);
}
}
EventTest
<?php
namespace Tests\Unit;
use Tests\TestCase;
use PHPUnit\Framework\Attributes\Test;
class EventTest extends TestCase
{
#[Test]
public function testLogLevelConstants(): void
{
$this->assertEquals(0, \IO\Event::LOG_DEBUG);
$this->assertEquals(1, \IO\Event::LOG_INFO);
$this->assertEquals(2, \IO\Event::LOG_WARNING);
$this->assertEquals(3, \IO\Event::LOG_ERROR);
$this->assertEquals(4, \IO\Event::LOG_CRITICAL);
}
#[Test]
public function testAddHandler(): void
{
\IO\Event::addHandler('custom', function ($level, $message, $context): mixed {
return $message;
});
$this->assertTrue(true);
}
#[Test]
public function testRemoveHandler(): void
{
\IO\Event::addHandler('test_handler');
\IO\Event::removeHandler('test_handler');
$this->assertTrue(true);
}
}
ContainerTest
<?php
namespace Tests\Unit;
use Tests\TestCase;
use PHPUnit\Framework\Attributes\Test;
class ContainerTest extends TestCase
{
#[Test]
public function testBindAndGet(): void
{
$container = new \IO\Container();
$container->bind('foo', fn (): string => 'bar');
$this->assertEquals('bar', $container->get('foo'));
}
#[Test]
public function testSingleton(): void
{
$container = new \IO\Container();
$container->singleton('service', fn (): \stdClass => new \stdClass());
$a = $container->get('service');
$b = $container->get('service');
$this->assertSame($a, $b);
}
#[Test]
public function testHas(): void
{
$container = new \IO\Container();
$container->bind('foo', 'bar');
$this->assertTrue($container->has('foo'));
$this->assertFalse($container->has('baz'));
}
}
Создание своих тестов
1. Создайте файл теста
php iocli make:test MyComponentTest
2. Напишите тест
<?php
namespace Tests\Unit;
use Tests\TestCase;
use PHPUnit\Framework\Attributes\Test;
class MyComponentTest extends TestCase
{
#[Test]
public function testSomething(): void
{
$result = myFunction();
$this->assertEquals('expected', $result);
}
#[Test]
public function testWithMock(): void
{
$mock = $this->createMock(SomeService::class);
$mock->method('getData')
->willReturn(['key' => 'value']);
$component = new MyComponent($mock);
$result = $component->process();
$this->assertEquals('value', $result['key']);
}
#[Test]
public function testException(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid argument');
new MyClass('invalid');
}
}
3. Запустите тест
php vendor/bin/phpunit tests/Unit/MyComponentTest.php
Моки и стабы
// Создание мока
$mock = $this->createMock(SomeService::class);
// Настройка возвращаемого значения
$mock->method('getData')
->willReturn(['key' => 'value']);
// Проверка вызова
$mock->expects($this->once())
->method('save')
->with($this->equalTo($data));
// Spy (проверка что метод был вызван)
$mock->expects($this->atLeastOnce())
->method('log');
Тестирование с контейнером
#[Test]
public function testWithContainer(): void
{
$container = new \IO\Container();
$container->setTestMode();
// Подмена сервиса
$container->instance('iodb', $mockDb);
$app = new \IO\App($container);
$result = $app->get('iodb');
$this->assertSame($mockDb, $result);
}
Конфигурация CI
# .github/workflows/test.yml
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
- run: composer install
- run: composer test:unit