VOOZH about

URL: https://deepwiki.com/calevans/staticforge/10-development-and-testing

⇱ Development & Testing | calevans/staticforge | DeepWiki


Loading...
Last indexed: 11 February 2026 (5f6a2a)
Menu

Development & Testing

This page provides guidance for developers contributing to StaticForge core or building custom features. It covers testing strategies, test infrastructure, development patterns, and best practices for extending the system.

For information about creating custom features as a user, see Creating Custom Features. For information about the core architecture that this page builds upon, see Core Architecture.


Testing Strategy

StaticForge uses a two-tier testing approach with PHPUnit:

Test TypePurposeScopeSpeedCoverage
Unit TestsTest individual classes and services in isolationSingle class/serviceFastComponent logic
Integration TestsTest complete workflows through the ApplicationFull systemSlowerEnd-to-end behavior

Test Directory Structure:

tests/
├── .env.testing # Unit test environment configuration
├── .env.integration # Integration test environment configuration
├── Unit/ # Unit tests
│ ├── UnitTestCase.php # Base class for unit tests
│ └── Features/ # Feature service tests
│ ├── Sitemap/
│ │ └── SitemapServiceTest.php
│ └── CacheBusterFeatureTest.php
└── Integration/ # Integration tests
 ├── IntegrationTestCase.php # Base class for integration tests
 ├── Commands/
 │ └── RenderSiteCommandTest.php
 ├── Features/
 │ └── RobotsTxtIntegrationTest.php
 └── RssFeedIntegrationTest.php

Sources: .gitattributes1-22 tests/Integration/Commands/RenderSiteCommandTest.php1-14 tests/Unit/Features/Sitemap/SitemapServiceTest.php1-11


Test Infrastructure

Base Test Classes

StaticForge provides two base test classes with common test utilities:


UnitTestCase provides:

  • Mock Container instance accessible via $this->container
  • setContainerVariable(string $key, mixed $value) - Set container variables for tests
  • getContainerVariable(string $key) - Retrieve container variables

IntegrationTestCase provides:

  • createContainer(string $envFile) - Load real Container from .env file
  • removeDirectory(string $dir) - Recursively delete test directories
  • Temporary directory management for isolated tests

Sources: tests/Unit/Features/Sitemap/SitemapServiceTest.php8-32 tests/Integration/Commands/RenderSiteCommandTest.php14-77


Unit Testing Pattern

Unit tests focus on individual services and components in isolation, mocking dependencies as needed.

Unit Test Structure


Example: Unit Testing a Service

tests/Unit/Features/Sitemap/SitemapServiceTest.php11-105 demonstrates the unit testing pattern:

Key characteristics:

  • Isolated testing: Service is instantiated with mocked Log dependency
  • Container mocking: Uses setContainerVariable() to configure test data
  • Temporary files: Creates temp directories for file I/O operations
  • Assertion focus: Each test method verifies a single behavior

Testing event handlers:

tests/Unit/Features/CacheBusterFeatureTest.php9-52 shows how to test feature event handlers:


Sources: tests/Unit/Features/Sitemap/SitemapServiceTest.php11-105 tests/Unit/Features/CacheBusterFeatureTest.php9-52


Integration Testing Pattern

Integration tests verify complete workflows through the full Application stack, testing feature interaction, file processing, and output generation.

Integration Test Lifecycle


Integration Test Structure

tests/Integration/RssFeedIntegrationTest.php9-267 demonstrates the integration testing pattern:

Setup pattern:


Test execution pattern:


Cleanup pattern:


Sources: tests/Integration/RssFeedIntegrationTest.php9-267 tests/Integration/Features/RobotsTxtIntegrationTest.php15-277


Command Testing

CLI commands require special testing considerations since they interact with Symfony Console.

Command Test Pattern


tests/Integration/Commands/RenderSiteCommandTest.php14-387 demonstrates command testing:

Basic command test:


Testing command options:


Testing error conditions:


Sources: tests/Integration/Commands/RenderSiteCommandTest.php14-387


Service-Oriented Development Pattern

StaticForge features follow a service-oriented architecture where complex features delegate to specialized service classes.

Feature + Service Architecture


Examples from codebase:

FeatureService ClassesResponsibilities
RssFeedRssFeedService
RssBuilder
Collect category files, generate RSS XML, build feed items
CategoryIndexCategoryService
ImageService
Scan categories, collect files, extract hero images, generate thumbnails
SitemapSitemapServiceCollect URLs during POST_RENDER, generate sitemap.xml during POST_LOOP
CacheBusterCacheBusterServiceGenerate unique build IDs, create cache-busting query strings

Service Implementation Pattern

src/Features/RssFeed/Services/RssFeedService.php13-305 demonstrates the service pattern:

Service structure:


Feature integration:


Benefits of this pattern:

  • Separation of concerns: Feature handles event registration, service handles domain logic
  • Testability: Services can be unit tested independently of the event system
  • Reusability: Services can be used by multiple features or contexts
  • Maintainability: Business logic is isolated from framework code

Sources: src/Features/RssFeed/Services/RssFeedService.php13-305 src/Features/Sitemap/Services/SitemapService.php10-122 src/Features/CategoryIndex/Services/CategoryService.php12-134 src/Features/CategoryIndex/Services/ImageService.php12-111 src/Features/CacheBuster/Feature.php12-53


Feature Manager and Discovery

Understanding how features are loaded is essential for testing and development.

Feature Discovery Priority System


Feature loading sequence: src/Core/FeatureManager.php48-96

  1. Load disabled features list from siteconfig.yaml['disabled_features']
  2. Load user features from src/Features/ (highest priority)
  3. Discover Composer features from vendor/composer/installed.json
  4. Load library features from vendor/eicc/staticforge/src/Features/ (lowest priority)
  5. Register each feature with EventManager and Container
  6. Store feature metadata in Container for audit commands

Feature class resolution: src/Core/FeatureManager.php239-280

The FeatureManager attempts to instantiate features using multiple namespace patterns:


This allows user features to override library features by matching the directory name.

Sources: src/Core/FeatureManager.php11-391


Testing Best Practices

Test Organization


Naming Conventions

Test TypeFile NamingClass NamingMethod Naming
Unit{Class}Test.php{Class}Testtest{BehaviorDescription}()
Integration{Feature}IntegrationTest.php{Feature}IntegrationTesttest{WorkflowDescription}()
Command{Command}Test.php{Command}Testtest{CommandName}With{Option}()

Examples:

  • Unit: SitemapServiceTest.phptestCollectUrl(), testGenerateSitemap()
  • Integration: RssFeedIntegrationTest.phptestGeneratesRssFeedForCategory()
  • Command: RenderSiteCommandTest.phptestRenderSiteCommandWithClean()

Test Data Management

Temporary directories: Use unique identifiers to prevent parallel test conflicts:


Test fixtures: Create minimal test content in setUp():


Cleanup: Always clean up in tearDown() to prevent disk space issues:


Sources: tests/Integration/RssFeedIntegrationTest.php19-70 tests/Unit/Features/Sitemap/SitemapServiceTest.php16-50


Environment Configuration for Tests

StaticForge uses separate environment files for unit and integration tests:

Test Environment Files

FilePurposeUsage
tests/.env.testingUnit test configurationMinimal settings, often overridden by tests
tests/.env.integrationIntegration test configurationFull application settings for end-to-end tests

Integration test environment: tests/.env.integration1-14


Loading test environments:


Sources: tests/.env.integration1-14 tests/Integration/Commands/RenderSiteCommandTest.php39-46


Running Tests

PHPUnit Configuration

StaticForge includes a phpunit.xml configuration file in the root directory (excluded from composer packages via .gitattributes14).

Running all tests:


Running specific test suites:


Verbose output:


Code coverage:


Continuous Integration

The .gitattributes file excludes test directories from Composer packages:

.gitattributes6-7

/tests export-ignore
/.github export-ignore

This ensures that when StaticForge is installed as a dependency, test files are not included in the vendor directory, reducing package size.

Sources: .gitattributes1-22


Development Workflow

Adding a New Feature


Debugging Tests

Enable verbose logging in tests:


Inspect container state:


Preserve temp directories for inspection:


Common Testing Pitfalls

IssueSymptomSolution
Parallel test conflictsRandom failures when running tests concurrentlyUse uniqid('', true) . '_' . getmypid() in temp paths
Container pollutionTests affect each other's container stateAlways call parent::setUp() and parent::tearDown()
Template not foundTwig errors in testsCreate minimal test template in setUp()
File permission errorsCan't write to temp directoriesCheck directory creation with 0755 permissions
Missing required configApplication fails during integration testsSet all required environment variables in test setUp()

Sources: tests/Integration/RssFeedIntegrationTest.php23-26 tests/Integration/Commands/RenderSiteCommandTest.php22-46


Extending Core Classes

When extending core StaticForge classes for custom functionality:

Safe Extension Points

ClassExtension MethodPurpose
BaseFeatureExtend and implement event handlersCreate custom features
BaseRendererFeatureExtend for content transformationCreate custom renderers
EventManagerAdd custom events via fire()Extend event system
ContainerUse setVariable()/add() for servicesRegister custom services

Unsafe Modifications

Do not modify:

  • Core event names (CREATE, POST_GLOB, RENDER, POST_RENDER, POST_LOOP, DESTROY)
  • Event parameter structure (always pass Container and array $parameters)
  • Container core methods (getVariable, setVariable, add, get)
  • FeatureManager loading sequence

Instead:

  • Use event priorities to control execution order
  • Create wrapper services if you need custom behavior
  • Extend base classes rather than modifying them
  • Submit pull requests for core changes

Sources: src/Core/FeatureManager.php11-391


Summary

StaticForge's testing and development infrastructure provides:

  • Two-tier testing: Unit tests for component logic, integration tests for workflows
  • Service-oriented architecture: Features delegate to testable service classes
  • Isolated test environments: Temporary directories and separate .env files
  • Base test classes: Common utilities via UnitTestCase and IntegrationTestCase
  • Feature discovery system: Priority-based loading with override capabilities

For more information on specific topics:

Sources: All cited files above