ForgeTesting is a comprehensive testing framework for Forge Engine applications. It provides a robust set of tools for unit testing, integration testing, HTTP testing, database testing, and performance benchmarking.
Module Type: Test Suite | Version: 0.1.1 | CLI Command: test
Rich set of assertion methods for validating test outcomes
Simulate HTTP requests and test responses with CSRF support
Test database operations and verify data integrity
Benchmark test execution and measure performance
Group tests, skip incomplete tests, and use data providers
Run tests from command line with filtering and grouping options
ForgeTesting comes pre-installed with Forge Engine. If you need to install it separately:
# Using Forge Package Manager
forge install forge-testing
# Manual installation
composer require forge/forge-testingForgeTesting is automatically configured when installed. The module registers itself and provides the test command through the CLI.
                            Create test classes by extending the TestCase base class and using test
                            attributes to define test methods.
                        
<?php
declare(strict_types=1);
namespace App\Tests;
use App\Modules\ForgeTesting\Attributes\Test;
use App\Modules\ForgeTesting\TestCase;
class ExampleTest extends TestCase
{
    #[Test('This is a test description')]
    public function test_something(): void
    {
        $this->assertTrue(true);
    }
}ForgeTesting provides several attributes to organize and control test execution:
#[Test]
                                Marks a method as a test method
#[Test('Optional description')]
public function my_test(): void
{
    // Test implementation
}#[Group]
                                Organizes tests into groups for selective execution
>#[Group('database')]
#[Test]
public function database_test(): void
{
    // Database-related test
}#[Skip]
                                Skips a test with an optional reason
#[Skip('Waiting for implementation')]
#[Test]
public function skipped_test(): void
{
    // This test will be skipped
}#[Incomplete]
                                Marks a test as incomplete with an optional reason
#[Incomplete('Needs performance optimization')]
#[Test]
public function incomplete_test(): void
{
    // This test is incomplete
}#[DataProvider]
                                Provides data to test methods for parameterized testing
#[DataProvider('userProvider')]
#[Test]
public function test_with_data(array $userData): void
{
    $this->assertArrayHasKey('email', $userData);
}
public function userProvider(): array
{
    return [
        [['email' => 'user1@example.com']],
        [['email' => 'user2@example.com']]
    ];
}ForgeTesting provides a comprehensive set of assertion methods for validating test outcomes:
assertTrue($condition)assertFalse($condition)assertEquals($expected, $actual)assertNotEquals($expected, $actual)assertInstanceOf($class, $object)assertNotInstanceOf($class, $object)assertSame($expected, $actual)assertNotSame($expected, $actual)assertArrayHasKey($key, $array)assertArrayNotHasKey($key, $array)assertCount($expected, $actual)assertDatabaseHas($table, $data)assertDatabaseMissing($table, $data)// Example usage
#[Test]
public function assertion_examples(): void
{
    // Basic assertions
    $this->assertTrue(true);
    $this->assertEquals('expected', 'actual');
    
    // Type assertions
    $this->assertInstanceOf(User::class, $user);
    $this->assertSame(123, 123); // Strict comparison
    
    // Array assertions
    $this->assertArrayHasKey('email', $userData);
    $this->assertCount(5, $items);
    
    // Database assertions
    $this->assertDatabaseHas('users', ['email' => 'test@example.com']);
}Test HTTP endpoints and responses with built-in CSRF protection support:
use App\Modules\ForgeTesting\Attributes\Test;
use App\Modules\ForgeTesting\TestCase;
class HttpTest extends TestCase
{
    #[Test]
    public function test_homepage(): void
    {
        $response = $this->get('/');
        $this->assertHttpStatus(200, $response);
    }
    #[Test]
    public function test_form_submission(): void
    {
        $response = $this->post('/login', [
            'email' => 'user@example.com',
            'password' => 'password'
        ]);
        
        $this->assertHttpStatus(302, $response);
    }
    #[Test]
    public function test_with_csrf(): void
    {
        // Load CSRF token
        $this->loadCsrfToken();
        
        $response = $this->withCsrf()->post('/api/data', [
            'data' => 'test'
        ]);
        
        $this->assertHttpStatus(200, $response);
    }
}
                                
                                Tip: Use withCsrf() to automatically include CSRF tokens
                                in your HTTP requests.
                            
Test database operations and verify data integrity with database-specific assertions:
use App\Modules\ForgeTesting\Attributes\Test;
use App\Modules\ForgeTesting\TestCase;
use Forge\Core\Database\QueryBuilder;
class DatabaseTest extends TestCase
{
    private QueryBuilder $queryBuilder;
    public function __construct()
    {
        $this->queryBuilder = new QueryBuilder();
    }
    #[Test('Create and verify user record')]
    public function create_user(): void
    {
        $user = new User();
        $user->email = 'test@example.com';
        $user->name = 'Test User';
        $user->save();
        $this->assertNotNull($user->id);
        $this->assertDatabaseHas('users', ['email' => 'test@example.com']);
    }
    #[Test('Delete user record')]
    public function delete_user(): void
    {
        $deleted = $this->queryBuilder
            ->reset()
            ->where('email', '=', 'test@example.com')
            ->setTable('users')
            ->delete();
        $this->assertTrue($deleted);
        $this->assertDatabaseMissing('users', ['email' => 'test@example.com']);
    }
}Benchmark your code execution and measure performance metrics:
use App\Modules\ForgeTesting\Attributes\Test;
use App\Modules\ForgeTesting\TestCase;
class PerformanceTest extends TestCase
{
    #[Test('Benchmark database query')]
    public function benchmark_user_lookup(): array
    {
        $results = $this->benchmark(function () {
            $this->assertDatabaseHas('users', ['email' => 'test@example.com']);
        }, 10); // Run 10 iterations
        return $results;
    }
    #[Test('Measure string processing performance')]
    public function benchmark_string_operations(): void
    {
        $results = $this->benchmark(function () {
            $string = 'this is a test string';
            $camelCase = Strings::toCamelCase($string);
            $this->assertEquals('thisIsATestString', $camelCase);
        });
        // Results contain execution time, memory usage, etc.
        $this->assertLessThan(0.1, $results['average_time']);
    }
}Execute tests using the Forge CLI with various filtering options:
# Run all tests
forge test
# Run tests for a specific module
forge test --module=ForgeAuth
# Run tests by group
forge test --group=database
# Run tests by type (app, engine, module)
forge test --type=app
forge test --type=engine
forge test --type=module
# Run tests with verbose output
forge test --verbosePro Tip: Use groups to organize related tests and run them selectively during development.
Here are comprehensive examples from different areas of testing:
#[Group('helpers')]
final class StringHelperTest extends TestCase
{
    #[Test('String converted to camelCase')]
    public function string_to_camel_case(): void
    {
        $expected = 'thisIsATest';
        $actual = Strings::toCamelCase('this is a test');
        $this->assertEquals($expected, $actual);
    }
    #[Test('String converted to PascalCase')]
    public function string_to_pascal_case(): void
    {
        $expected = 'ThisIsATest';
        $actual = Strings::toPascalCase('this is a test');
        $this->assertEquals($expected, $actual);
    }
    #[Test('String converted to-friendly-url')]
    public function string_to_friendly_url(): void
    {
        $expected = 'this-is-a-test';
        $actual = Strings::slugify('this is a test');
        $this->assertEquals($expected, $actual);
    }
}#[Group('auth')]
final class AuthenticationTest extends TestCase
{
    #[Test('User login functionality')]
    #[Skip('Waiting on implementation')]
    public function login_works(): void
    {
        $this->assertTrue(true);
    }
    #[Test('Check a record exists in the database by identifier')]
    #[Group('database')]
    public function user_exists(): void
    {
        $this->assertDatabaseHas('users', ['identifier' => 'example']);
    }
    #[DataProvider('userProvider')]
    #[Test]
    #[Group('database')]
    public function multiple_users(array $users): void
    {
        $this->assertArrayHasKey('email', $users);
    }
    #[Test('Benchmark user lookup')]
    #[Group('database')]
    public function benchmark_user_lookup(): array
    {
        $results = $this->benchmark(function () {
            $this->assertDatabaseHas('users', ['email' => 'test@example.com']);
        }, 1);
        return $results;
    }
}#[Group] attribute#[Test] attributetearDown() methods#[Skip] for tests that are not ready#[Incomplete] and provide reasons