Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Lifecycle Laravel Package

testo/lifecycle

Lifecycle hooks plugin for the Testo PHP testing framework. Adds setup/teardown around individual tests and entire test classes to manage fixtures, external resources, and cleanup between runs. Install via composer require --dev testo/lifecycle.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Install the Package Add the package to your project via Composer:

    composer require --dev testo/lifecycle
    
  2. Enable the Plugin Register the lifecycle plugin in your Testo configuration (typically in testo.php or via CLI):

    use Testo\Lifecycle\LifecyclePlugin;
    
    return [
        'plugins' => [
            LifecyclePlugin::class,
        ],
    ];
    
  3. First Use Case: Basic Hooks Annotate a test class with lifecycle hooks:

    use Testo\Annotations\BeforeClass;
    use Testo\Annotations\AfterClass;
    use Testo\Annotations\Before;
    use Testo\Annotations\After;
    
    #[BeforeClass]
    public function setUpClass(): void
    {
        // Runs once before all tests in the class
        $this->sharedResource = new SharedResource();
    }
    
    #[AfterClass]
    public function tearDownClass(): void
    {
        // Runs once after all tests in the class
        $this->sharedResource->cleanup();
    }
    
    #[Before]
    public function setUp(): void
    {
        // Runs before each test
        $this->testData = $this->generateTestData();
    }
    
    #[After]
    public function tearDown(): void
    {
        // Runs after each test
        unset($this->testData);
    }
    
    public function test_example(): void
    {
        // Your test logic
    }
    
  4. Run Tests Execute your tests using Testo’s CLI:

    ./vendor/bin/testo
    

Implementation Patterns

Usage Patterns

  1. Class-Level Lifecycle Management Use @BeforeClass and @AfterClass for setup/teardown that should run once per test class (e.g., database connections, API clients, or heavy fixtures).

    #[BeforeClass]
    public function createTestDatabase(): void
    {
        $this->db = new TestDatabase();
        $this->db->seed();
    }
    
    #[AfterClass]
    public function dropTestDatabase(): void
    {
        $this->db->drop();
    }
    
  2. Per-Test Lifecycle Management Use @Before and @After for setup/teardown that should run before/after each test (e.g., temporary files, mocks, or test-specific data).

    #[Before]
    public function setUpTestData(): void
    {
        $this->testUser = User::factory()->create();
    }
    
    #[After]
    public function deleteTestData(): void
    {
        $this->testUser->delete();
    }
    
  3. Conditional Hooks Dynamically enable/disable hooks based on test conditions or environment variables:

    #[Before]
    public function conditionalSetup(): void
    {
        if (getenv('TEST_WITH_MOCKS')) {
            $this->mockService = $this->createMock(Service::class);
        }
    }
    
  4. Dependency Injection Inject dependencies into lifecycle methods via Testo’s DI container:

    #[BeforeClass]
    public function setUpWithDependencies(Logger $logger): void
    {
        $this->logger = $logger;
        $this->logger->info('Setting up test class');
    }
    
  5. Shared Fixtures Use class-level hooks to load shared fixtures for all tests in a class:

    #[BeforeClass]
    public function loadSharedFixtures(): void
    {
        FixtureLoader::load('shared_fixtures.yaml');
    }
    

Workflows

  1. Fixture-Driven Testing

    • Use @BeforeClass to load fixtures once per class.
    • Use @AfterClass to clean up fixtures.
    • Example: Database seeding for integration tests.
  2. Resource Management

    • Use @Before to open connections/files/services.
    • Use @After to close/clean up resources.
    • Example: Temporary file handling or API client sessions.
  3. Test Isolation

    • Ensure each test starts with a clean state by resetting dependencies in @Before.
    • Clean up after each test in @After to avoid side effects.
  4. Hybrid Testing

    • Combine lifecycle hooks with Testo’s built-in features like async tests or mocking.
    • Example: Set up a mock HTTP client in @BeforeClass and use it across tests.

Integration Tips

  1. Leverage Testo’s Annotations Familiarize yourself with Testo’s annotation system (@test, @group, etc.) to combine lifecycle hooks with other test metadata.

  2. Combine with Testo Plugins Integrate testo/lifecycle with other Testo plugins (e.g., testo/database for database testing) for seamless workflows:

    use Testo\Database\DatabasePlugin;
    
    return [
        'plugins' => [
            DatabasePlugin::class,
            LifecyclePlugin::class,
        ],
    ];
    
  3. Custom Hook Logic Extend the lifecycle behavior by creating custom methods and calling them from hooks:

    #[Before]
    public function prepareTestEnvironment(): void
    {
        $this->setupMocks();
        $this->configureTestData();
    }
    
    private function setupMocks(): void
    {
        // Custom mock setup logic
    }
    
  4. Test Organization Group related tests into classes and use @BeforeClass/@AfterClass to manage shared resources efficiently.

  5. CI/CD Optimization Use lifecycle hooks to optimize test runs in CI by:

    • Setting up expensive resources once per class (@BeforeClass).
    • Parallelizing test execution where possible (Testo supports parallel tests).

Gotchas and Tips

Pitfalls

  1. Hook Execution Order

    • Class-level hooks (@BeforeClass, @AfterClass) run once per class, while per-test hooks (@Before, @After) run before/after each test.
    • Ensure @BeforeClass completes before @Before and @AfterClass runs after @After.
    • Pitfall: Forgetting that @AfterClass runs after all tests, including failures.
  2. State Leakage

    • Avoid storing shared state in class properties between tests unless explicitly managed in hooks.
    • Pitfall: Accidentally leaving resources open or data modified between tests.
  3. Exception Handling

    • Exceptions in lifecycle methods will fail the entire test suite unless caught and handled gracefully.
    • Pitfall: Unhandled exceptions in @BeforeClass can prevent tests from running.
  4. Annotation Conflicts

    • Ensure annotations are correctly placed (e.g., @Before must be on a method, not a property).
    • Pitfall: Misplaced annotations may be ignored or cause errors.
  5. Plugin Compatibility

    • Some Testo plugins may interfere with lifecycle hooks. Test thoroughly after adding new plugins.
    • Pitfall: Unexpected behavior if plugins override or modify lifecycle execution.
  6. Performance Overhead

    • Overusing @Before/@After for lightweight operations can slow down tests.
    • Pitfall: Adding unnecessary hooks for trivial setup/teardown.

Debugging

  1. Hook Not Triggering

    • Verify the plugin is registered in testo.php.
    • Check for syntax errors in annotations (e.g., typos in #[]).
    • Debug Tip: Use Testo\Annotations\Before directly in code to test hook execution:
      #[Before]
      public function debugHook(): void
      {
          error_log('Hook executed!');
      }
      
  2. Hook Failing Silently

    • Wrap hook logic in try-catch blocks to log errors:
      #[Before]
      public function setupWithErrorHandling(): void
      {
          try {
              $this->setupLogic();
          } catch (\Throwable $e) {
              error_log('Setup failed: ' . $e->getMessage());
              throw $e;
          }
      }
      
  3. Test Isolation Issues

    • If tests interfere with each other, check for shared state or improper cleanup in @After.
    • Debug Tip: Add assertions in @After to verify cleanup:
      #[After]
      public function verifyCleanup(): void
      {
          $this->assertNull($this->testData, 'Test data not cleaned up!');
      }
      
  4. Plugin Registration Errors

    • Ensure LifecyclePlugin::class is correctly spelled and autoloaded.
    • Debug Tip: Clear Composer’s cache and reinstall dependencies:
      composer clear-cache
      composer install
      

Config Quirks

  1. Annotation Syntax

    • Use shortcut syntax (#[Before]) instead of @Before if your PHP version supports attributes (PHP 8+).
    • Quirk: Older PHP versions may require the @ syntax.
  2. Method Visibility

    • Lifecycle methods must be public to be detected by the plugin.
    • Quirk: Protected/private methods are ignored.
  3. Static vs. Instance Methods

    • Lifecycle methods **must be
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
sentix/ai-chatbot
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky