Skip to content

Migrate Existing Project ​

This guide shows how to add TestLink to an existing project with pre-existing tests.

Overview ​

Migration involves:

  1. Installing packages
  2. Identifying critical code to link
  3. Adding links incrementally
  4. Setting up validation

Step 1: Install Packages ​

bash
# Production dependency - attributes
composer require testflowlabs/test-attributes

# Dev dependency - CLI tools
composer require --dev testflowlabs/testlink

Step 2: Verify Installation ​

bash
./vendor/bin/testlink report

You should see an empty report (no links exist yet):

Coverage Links Report
─────────────────────

No coverage links found.

Step 3: Choose a Migration Strategy ​

Start with the most critical production code:

  1. Identify core business logic
  2. Add #[TestedBy] to those methods
  3. Run sync to add test links
  4. Expand gradually

Strategy B: Bottom-Up ​

Start with tests:

  1. Add test links (->linksAndCovers() / #[LinksAndCovers] / @see) to existing tests
  2. Run sync to add production links
  3. Validate and expand

Strategy C: Feature-by-Feature ​

Add links when working on features:

  1. When you touch a file, add its links
  2. New code always gets links
  3. Eventually full coverage

Step 4: Start Linking (Top-Down Example) ​

4.1 Identify critical classes ​

Choose your most important classes:

src/
├── Services/
│   ├── UserService.php      ← Start here
│   ├── OrderService.php     ← Then here
│   └── PaymentService.php   ← Then here

4.2 Add attributes to production ​

php
<?php
// src/Services/UserService.php

namespace App\Services;

use TestFlowLabs\TestingAttributes\TestedBy;

class UserService
{
    #[TestedBy('Tests\Unit\UserServiceTest', 'test_creates_user')]
    #[TestedBy('Tests\Unit\UserServiceTest', 'test_validates_email')]
    public function create(array $data): User
    {
        // existing implementation
    }

    #[TestedBy('Tests\Unit\UserServiceTest', 'test_finds_user_by_id')]
    public function find(int $id): ?User
    {
        // existing implementation
    }
}

4.3 Run sync to update tests ​

bash
# Preview changes
./vendor/bin/testlink sync --dry-run

# Apply changes
./vendor/bin/testlink sync

4.4 Validate ​

bash
./vendor/bin/testlink validate

Step 5: Handle Common Situations ​

Tests without matching methods ​

If your test names don't match method names:

php
// Test name
public function test_it_should_create_a_user()

// Doesn't match production method name
// Use the actual test name in TestedBy
#[TestedBy('Tests\UserServiceTest', 'test_it_should_create_a_user')]

Multiple test classes for one production class ​

php
#[TestedBy('Tests\Unit\UserServiceTest', 'test_creates_user')]
#[TestedBy('Tests\Integration\UserFlowTest', 'test_user_registration_flow')]
public function create(array $data): User

Legacy tests without clear method mapping ​

Start with links() instead of linksAndCovers() for integration tests:

php
test('legacy integration test', function () {
    // Tests multiple things
})
->links(UserService::class.'::create')
->links(UserService::class.'::validate');

Step 6: Set Up CI ​

Add validation to your CI pipeline:

yaml
# .github/workflows/test.yml
- name: TestLink Validation
  run: ./vendor/bin/testlink validate

Start with warnings allowed, then enable strict mode:

yaml
# Phase 1: Allow warnings
- run: ./vendor/bin/testlink validate

# Phase 2 (later): Strict mode
- run: ./vendor/bin/testlink validate --strict

Migration Checklist ​

Week 1 ​

  • [ ] Install packages
  • [ ] Link 1-2 critical classes
  • [ ] Run validation locally

Week 2-4 ​

  • [ ] Link remaining core services
  • [ ] Add to CI (non-blocking)
  • [ ] Document approach for team

Month 2+ ​

  • [ ] Link all new code
  • [ ] Gradually link existing code
  • [ ] Enable strict CI validation

Tips for Large Codebases ​

Use path filtering ​

Focus on specific directories:

bash
./vendor/bin/testlink report --path=src/Services
./vendor/bin/testlink validate --path=src/Services

Track progress ​

bash
# Count linked methods
./vendor/bin/testlink report --json | jq '.summary.methodsWithTests'

# Count unlinked methods
./vendor/bin/testlink report --json | jq '.summary.methodsWithoutTests'

Batch linking ​

For classes with many methods, add links in batches:

bash
# This week: UserService
# Next week: OrderService
# Week after: PaymentService

Common Mistakes to Avoid ​

  1. Don't try to link everything at once - It's overwhelming
  2. Don't skip validation - Run it regularly
  3. Don't forget integration tests - Use links() for them
  4. Don't ignore existing test names - Use them exactly as written

Measuring Success ​

Track these metrics:

MetricStartTarget
Methods with links080%+
Validation errorsN/A0
CI passesN/A100%

Released under the MIT License.