unit test strategy
Drupal AI Unit Test Strategy
Coverage Target: 80%+ Framework: PHPUnit 10+ Test Types: Unit, Kernel, Functional
Quick Test Examples
Test AI Provider
<?php namespace Drupal\Tests\ai_provider_gitlab\Unit; use Drupal\ai_provider_gitlab\Plugin\AiProvider\GitLabAiGateway; use Drupal\Tests\UnitTestCase; class GitLabAiGatewayTest extends UnitTestCase { public function testChatOperation(): void { $http_client = $this->createMock('GuzzleHttp\ClientInterface'); $http_client->method('request') ->willReturn(new Response(200, [], json_encode([ 'choices' => [['message' => ['content' => 'Test response']]], 'usage' => ['total_tokens' => 100], ]))); $provider = new GitLabAiGateway([], 'gitlab_ai_gateway', []); $provider->setHttpClient($http_client); $output = $provider->chat('Test prompt', 'claude-sonnet-4'); $this->assertEquals('Test response', $output->getNormalized()); $this->assertEquals(100, $output->getUsage()['total_tokens']); } }
Test OSSA Export
<?php namespace Drupal\Tests\ai_agents_ossa\Kernel; use Drupal\KernelTests\KernelTestBase; use Drupal\ai_agents\Entity\Agent; class OssaBridgeTest extends KernelTestBase { protected static $modules = ['ai', 'ai_agents', 'ai_agents_ossa']; public function testManifestExport(): void { $agent = Agent::create([ 'id' => 'test_agent', 'label' => 'Test Agent', 'description' => 'Test agent for OSSA export', 'provider' => 'gitlab_ai_gateway', 'model' => 'claude-sonnet-4', ]); $agent->save(); $bridge = \Drupal::service('ai_agents_ossa.bridge'); $manifest = $bridge->exportAgent($agent); $this->assertEquals('ossa.bluefly.io/v0.2.8', $manifest['apiVersion']); $this->assertEquals('Agent', $manifest['kind']); $this->assertArrayHasKey('metadata', $manifest); $this->assertArrayHasKey('spec', $manifest); } }
Test ECA AI Action
<?php namespace Drupal\Tests\eca_ai\Functional; use Drupal\Tests\BrowserTestBase; class GenerateTextActionTest extends BrowserTestBase { protected static $modules = ['eca', 'eca_ai', 'ai', 'node']; public function testTextGeneration(): void { $this->drupalLogin($this->drupalCreateUser(['administer eca'])); // Create ECA model with AI action $this->drupalGet('/admin/config/workflow/eca/add'); // ... configure AI text generation action // Trigger event $node = $this->drupalCreateNode(); // Assert AI-generated content $this->assertNotEmpty($node->get('field_summary')->value); } }
Test Coverage Strategy
Critical Paths (100% coverage)
- AI provider chat/embeddings methods
- OSSA manifest generation/validation
- Token usage tracking
- Error handling
High Priority (90% coverage)
- ECA AI action execution
- Agent tool execution
- Configuration validation
- Security (XSS, injection prevention)
Medium Priority (75% coverage)
- UI forms and validation
- Admin pages
- Drush commands
Automated Testing
Pre-commit Hook
# .husky/pre-commit #!/bin/bash ddev exec vendor/bin/phpunit --coverage-text --coverage-clover coverage.xml coverage=$(grep -oP 'Lines:\s+\K[\d.]+' coverage.xml | head -1) if [ $(echo "$coverage < 80" | bc) -eq 1 ]; then echo " Coverage below 80% ($coverage%)" exit 1 fi
CI/CD Pipeline
# .gitlab-ci.yml test: stage: test script: - ddev start - ddev exec vendor/bin/phpunit --coverage-clover coverage.xml - ddev exec vendor/bin/phpstan analyse coverage: '/Lines:\s+(\d+\.\d+)%/' artifacts: reports: coverage_report: coverage_format: cobertura path: coverage.xml
Mock Strategies
Mock AI Provider Responses
// Mock GitLab AI Gateway $mock_response = [ 'choices' => [['message' => ['content' => 'Mocked response']]], 'usage' => ['total_tokens' => 50], ]; $http_client = $this->createMock('GuzzleHttp\ClientInterface'); $http_client->method('request') ->willReturn(new Response(200, [], json_encode($mock_response)));
Mock Agent Execution
// Mock agent for testing workflows $agent = $this->createMock('Drupal\ai_agents\Entity\AgentInterface'); $agent->method('execute') ->willReturn(new ExecutionResult(['status' => 'success']));
Performance Testing
// Test response time public function testResponseTime(): void { $start = microtime(true); $provider->chat('Test', 'claude-sonnet-4'); $duration = microtime(true) - $start; $this->assertLessThan(2.0, $duration, 'Response time > 2s'); }
Run Tests
# All tests ddev exec vendor/bin/phpunit # Specific test ddev exec vendor/bin/phpunit tests/src/Unit/GitLabAiGatewayTest.php # With coverage ddev exec vendor/bin/phpunit --coverage-html coverage/
References
- PHPUnit Docs: https://phpunit.de/
- Drupal Testing: https://www.drupal.org/docs/automated-testing