Skip to content

Enhanced Testing Utilities & Mock Server #48

@Thavarshan

Description

@Thavarshan

Summary

Add comprehensive testing utilities including a powerful mock server, request recording/playback, and advanced assertion helpers for HTTP testing.

Motivation

Testing utilities are essential for:

  • Test Reliability: Consistent, predictable test responses
  • Development Speed: Fast test execution without external dependencies
  • Integration Testing: Complex request/response scenarios
  • Contract Testing: Verify API contracts and compatibility
  • Edge Case Testing: Simulate error conditions and edge cases

Proposed API

// Mock server with request matching
MockServer::fake([
    'GET /api/users' => MockResponse::json(['users' => []]),
    'POST /api/users' => MockResponse::create(201)->delay(100),
    'GET /api/users/*' => MockResponse::json(['id' => 1, 'name' => 'John']),
    '/api/error' => MockResponse::sequence([
        MockResponse::create(500),
        MockResponse::create(200),
    ]),
]);

// Advanced request assertions
MockServer::assertSent('POST /api/users', function (Request $request) {
    return $request->hasHeader('Authorization') &&
           $request->json()['name'] === 'John Doe';
});

// Record and replay
Recorder::start();
$response = fetch('/api/real-endpoint');
$recordings = Recorder::stop();

// Later, replay the recorded responses
MockServer::replay($recordings);

Implementation Details

class MockServer
{
    private static array $routes = [];
    private static array $sentRequests = [];
    
    public static function fake(array $routes): void
    {
        self::$routes = $routes;
        self::$sentRequests = [];
        
        // Override HTTP client to use mock responses
        HttpClientFactory::setMockMode(true);
    }
    
    public static function assertSent(string $pattern, callable $callback = null): void
    {
        $matching = array_filter(self::$sentRequests, function ($request) use ($pattern, $callback) {
            return self::matchesPattern($request, $pattern) &&
                   ($callback === null || $callback($request));
        });
        
        if (empty($matching)) {
            throw new AssertionFailedException("No requests sent matching: $pattern");
        }
    }
    
    public static function assertNotSent(string $pattern): void
    {
        // Implementation
    }
    
    public static function assertSentCount(string $pattern, int $count): void
    {
        // Implementation
    }
}

class MockResponse
{
    public static function json(array $data, int $status = 200): self
    {
        return new self($status, ['Content-Type' => 'application/json'], json_encode($data));
    }
    
    public static function create(int $status, array $headers = [], string $body = ''): self
    {
        return new self($status, $headers, $body);
    }
    
    public function delay(int $milliseconds): self
    {
        $this->delay = $milliseconds;
        return $this;
    }
    
    public function times(int $count): self
    {
        $this->times = $count;
        return $this;
    }
}

Benefits

  • Test Quality: More reliable and comprehensive tests
  • Development Speed: Faster test execution
  • Isolation: Tests don't depend on external services
  • Edge Cases: Easy simulation of error conditions

Priority

High Impact, Medium Effort - Critical for testing but requires significant implementation work.

Metadata

Metadata

Assignees

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions