Skip to content

Testing

Ray Fung edited this page Feb 26, 2026 · 5 revisions

Testing

Razy uses PHPUnit 10.5 for testing with 4,564 test cases, 8,178 assertions, and 0 skipped tests across 102 test classes. The framework follows PSR-12 coding standards enforced by PHP CS Fixer.

Running Tests

# Run all tests

vendor/bin/phpunit



# Run a specific test class

vendor/bin/phpunit tests/CollectionTest.php



# Run with coverage report (HTML)

vendor/bin/phpunit --coverage-html coverage/



# Filter specific test method

vendor/bin/phpunit --filter testSelectQuery

Test Suite Files

| Category | Test Classes | Covers |

| --- | --- | --- |

| Collection & Data | CollectionTest, ChunkCollectionTest, HashMapTest, ConfigurationTest, ConfigLoaderTest | Selector, filtering, serialisation, dot-path, lazy-load |

| Database & SQL | StatementTest, StatementPoolTest, SimpleSyntaxTest, DatabaseDriverTest, DatabaseDriverRegistryTest, DatabaseTransactionTest, DatabaseQueryHistoryTest, TableHelperTest, FetchModeTest, QueryBuilderEnhancedTest, ValueEscapeTest | SELECT/INSERT/UPDATE/DELETE, JOINs, Simple Syntax, drivers, schema DDL |

| ORM | ORMTest, EagerLoadingTest, SoftDeletesTest, ModelEventsTest, AttributeSerializationTest, BelongsToManyTest, QueryScopesTest, ConvenienceMethodsTest, PaginatorTest, ControllerLoadModelTest | Models, relations, scopes, pagination, soft deletes |

| Migration | MigrationTest, ControllerMigrationTest, ChangeTypeTest | Schema migrations, column type changes |

| Template | TemplateTest, BlockNestingTest, CompiledTemplateTest, ParameterBagTraitTest, ExitRemovalTest | Blocks, modifiers, function tags, compiled output |

| Routing | RouteTest, RouteGroupTest, RouteDispatcherTest, NamedRoutesTest, HttpMethodRoutingTest, RouteRegexCompileTest | Pattern matching, groups, named routes, HTTP methods |

| Container & DI | ContainerTest, ContainerEnhancedTest, ContainerRebindTest, ContextualBindingTest, DIIntegrationTest, InterfaceMockTest, InterfaceUserScenarioTest | Bindings, auto-wiring, PSR-11, contextual binding |

| Security | CryptTest, CsrfTest, AuthenticatorTest, AuthTest, SessionTest, SessionDriverTest | AES-256, CSRF tokens, TOTP/HOTP, sessions |

| Cache | CacheTest, RedisAdapterTest | PSR-16, FileAdapter, NullAdapter, Redis |

| Queue & Rate Limit | JobQueueTest, RateLimitTest | Job dispatching, token bucket / sliding window |

| HTTP & IO | HttpClientTest, FTPClientTest, SFTPClientTest, FileReaderTest, SimplifiedMessageTest, NotificationTest | HTTP client, FTP/SFTP, file reading, notifications |

| Pipeline & Middleware | PipelineTest, MiddlewareTest, MiddlewareGroupRegistryTest, FormRequestTest | Pipeline stages, middleware groups, form validation |

| Events | EventDispatcherTest, PSR14EventTest | Event emitters, PSR-14 compliance |

| Module System | ModuleTest, ModuleStatusTest, ModuleChangeDetectorTest, ModuleRegistryListenerTest, AgentTest, PluginManagerTest, DomainTest | Module lifecycle, status, change detection, plugins |

| CLI & Deployment | TerminalTest, CaddyfileCompilerTest, WorkerLifecycleManagerTest, WorkerModeResetTest, WorkerStateTest, RestartSignalTest | CLI commands, Caddyfile generation, worker mode |

| Validation | ValidationTest, NestedValidationTest | Rule-based validation, nested data |

| Logging | LoggerTest, LogChannelTest, ProfilerTest | Log channels, profiling |

| Error Handling | ErrorTest, ExceptionTest | Custom exceptions, error handling |

| Environment | EnvTest | .env file parsing |

| YAML | YAMLTest, YAMLParserTest, YAMLDumperTest | Parse, encode, decode, edge cases |

| DOM & Utilities | DOMTest, UtilTest | DOM builder, utility functions |

PHPUnit Configuration

The project's phpunit.xml is in the root directory:


<?xml version="1.0" encoding="UTF-8"?>

<phpunit

    bootstrap="tests/bootstrap.php"

    colors="true"

    stopOnFailure="false">

  <testsuites>

    <testsuite name="Razy Tests">

      <directory>tests</directory>

    </testsuite>

  </testsuites>

  <source>

    <include>

      <directory>src/library</directory>

    </include>

  </source>

</phpunit>

Writing Tests

Basic Test — Collection

namespace Tests;



use PHPUnit\Framework\TestCase;

use Razy\Collection;



class CollectionTest extends TestCase

{

    public function testSelectorAccess(): void

    {

        $data = new Collection([

            'users' => [

                ['name' => 'Alice'],

            ],

        ]);



        $result = $data('users.0.name');

        $this->assertEquals('Alice', $result);

    }

}

Database Statement Tests

namespace Tests;



use PHPUnit\Framework\TestCase;

use Razy\Database;

use Razy\Database\Statement;



class StatementTest extends TestCase

{

    private Database $db;



    protected function setUp(): void

    {

        $this->db = new Database('test');

    }



    public function testSelectBuilder(): void

    {

        $stmt = $this->db->prepare()

            ->select('id, name')

            ->from('users')

            ->where('active=:active')

            ->order('<name')

            ->limit(0, 10);



        $this->assertInstanceOf(Statement::class, $stmt);

    }



    public function testInsertBuilder(): void

    {

        $stmt = $this->db->insert('users', ['name', 'email']);

        $stmt->assign(['name' => 'Alice', 'email' => 'alice@example.com']);



        $this->assertInstanceOf(Statement::class, $stmt);

    }

}

Template Engine Tests

namespace Tests;



use PHPUnit\Framework\TestCase;

use Razy\Template;



class TemplateTest extends TestCase

{

    public function testVariableAssignment(): void

    {

        $tpl = new Template();

        $source = $tpl->loadFromString('<h1>{$title}</h1>');

        $source->assign('title', 'Hello');



        $output = $source->output();

        $this->assertStringContainsString('Hello', $output);

    }



    public function testBlockRendering(): void

    {

        $markup = implode("\n", [

            '<!-- BEGIN BLOCK items -->',

            '<li>{$value}</li>',

            '<!-- END BLOCK items -->',

        ]);



        $tpl = new Template();

        $source = $tpl->loadFromString($markup);

        $entity = $source->newBlock('items');

        $entity->assign('value', 'Apple');



        $output = $source->output();

        $this->assertStringContainsString('Apple', $output);

    }

}

Utility Function Tests

namespace Tests;



use PHPUnit\Framework\TestCase;

use Razy\Util\PathUtil;

use Razy\Util\VersionUtil;

use Razy\Util\ArrayUtil;



class UtilTest extends TestCase

{

    public function testPathAppend(): void

    {

        $result = PathUtil::append('/var/www', 'sites', 'mysite');

        $this->assertStringEndsWith('mysite', $result);

    }



    public function testVersionCompare(): void

    {

        $this->assertTrue(VersionUtil::vc('>=1.0.0', '1.2.3'));

        $this->assertFalse(VersionUtil::vc('>=2.0.0', '1.2.3'));

    }



    public function testArrayComparison(): void

    {

        $this->assertTrue(ArrayUtil::comparison(10, 5, '>'));

        $this->assertTrue(ArrayUtil::comparison('hello', 'he', '^='));

        $this->assertFalse(ArrayUtil::comparison('world', 'xyz', '*='));

    }

}

Coding Standards

# Run PHP CS Fixer (PSR-12)

vendor/bin/php-cs-fixer fix src/ --rules=@PSR12



# Dry-run to check without changing files

vendor/bin/php-cs-fixer fix src/ --rules=@PSR12 --dry-run

Module Validation

# Validate module structure

php Razy.phar validate



# Checks:

# - module.php returns valid ModuleInfo

# - package.php matches expected schema

# - Controller class exists and extends correctly

# - Route configurations are valid

← PreviousCLI & Terminal

Next → API Reference

Clone this wiki locally