Skip to content
Back to skills

Test Performance

ASecurity

Use when optimizing test suite performance — database setup, seeder optimization, parallel testing, CI pipeline efficiency, or RefreshDatabase alternatives.

  • 10 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added June 5, 2026
ai-agentsgophpbashsqltestingapidatabaseperformance

Works with

  • api

Security analysis

A100/100

Scanned June 5, 2026

npx -y skills add event4u-app/agent-config --skill test-performance --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Test Performance?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Test Performance
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/event4u-app-test-performance/badge)](https://www.skillsdirectory.com/skills/event4u-app-test-performance)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
model_tier: medium
name: test-performance
description: "Use when optimizing test suite performance — database setup, seeder optimization, parallel testing, CI pipeline efficiency, or RefreshDatabase alternatives."
domain: quality
framework: laravel
workspaces:
  - engineering
packs:
  - engineering-base
---

# test-performance

## When to use

Use this skill when:

- Tests are running too slowly (locally or in CI)
- Database setup/teardown is a bottleneck
- Parallel testing needs optimization
- Seeders need performance analysis
- CI pipeline test jobs need to be faster
- Investigating flaky tests caused by database state

## Procedure: Analyze test performance

### 1. Measure baseline

Before optimizing, always measure:

```bash
# Count tests per suite
find tests/ app/Modules/*/Tests/ -name "*.php" | xargs grep -l "it(" | wc -l

# Count by suite type
grep -rh "it(" tests/Unit/ app/Modules/*/Tests/Unit/ --include="*.php" | wc -l
grep -rh "it(" tests/Component/ app/Modules/*/Tests/Component/ --include="*.php" | wc -l
grep -rh "it(" tests/Integration/ app/Modules/*/Tests/Integration/ --include="*.php" | wc -l

# Count migrations
ls database/migrations/*.php | wc -l

# Count seeders
find database/seeders database/seeder-data -name "*.php" -path "*/data/*" | wc -l
```

### 2. Identify bottlenecks

The typical test lifecycle is:

```
Process Start → Migrate → Seed → [Test → Rollback] × N → Process End
                 ↑ expensive (once per worker)
```

Check these areas in order of typical impact:

| Area | What to check | Typical impact |
|------|--------------|---------------|
| **Migration count** | How many CREATE TABLE statements? | High if >20 |
| **Schema dump** | Is `database/schema/` used? | High if missing |
| **Seeder INSERT method** | Individual `save()` vs bulk insert? | Medium |
| **Truncation** | Per-seeder truncate vs centralized? | Low (but causes correctness issues) |
| **Connection discovery** | Dynamic `getPdo()` probing? | Low |
| **Parallel worker setup** | Does each worker re-migrate? | High |

### 3. Optimization strategies (ordered by ROI)

#### A. Schema Dump (highest ROI)

Laravel's `schema:dump` consolidates all migrations into one SQL file.
Instead of running N individual CREATE TABLE migrations, it loads one SQL dump.

```bash
php artisan schema:dump --database=api_database
# Generates database/schema/api_database-schema.sql
```

**Savings:** 58 migrations → 1 SQL load = ~10-25s per worker.

#### B. Template DB Cloning (high ROI for parallel tests)

Instead of each parallel worker running migrate+seed independently:
1. Prepare ONE template database (migrate + seed)
2. Clone template for each worker via mysqldump

```bash
# Prepare template
php artisan migrate:fresh --database=template_db
php artisan db:seed --database=template_db

# Clone per worker
mysqldump template_db | mysql worker_db_test_1
```

**Savings:** Eliminate per-worker migrate+seed entirely.

#### C. Skip Migrate+Seed Flag (high ROI for local dev)

Add a config flag to skip database setup when DB is already prepared:

```php
// config/testing.php
'skip_migrate_seed' => EnvHelper::boolean('TESTING_SKIP_MIGRATE_SEED', false),
```

Developer workflow: `make migrate-testing` once, then `make test-quick` repeatedly.

#### D. Bulk Inserts in Seeders (medium ROI)

Replace individual `$model->save()` with bulk insert:

```php
// Before: N INSERT statements
foreach ($data as $row) {
    $model = new MyModel($row);
    $model->save();
}

// After: 1 INSERT statement
MyModel::insert($data);
$models = MyModel::whereIn('id', $ids)->get();
```

#### E. Centralize Truncation (correctness fix)

Per-seeder truncation is redundant after `migrate:fresh` and causes:
- Non-deterministic ordering (lazy init triggers truncate)
- Ghost data bugs (locally passes, CI fails)

Make truncation configurable, default off:

```php
// config/testing.php
'seed_truncate' => EnvHelper::boolean('DB_SEED_TRUNCATE', false),
```

#### F. Static Connection Discovery (cleanup)

Replace dynamic `getPdo()` probing with explicit config:

```php
// config/testing.php
'connections_to_transact' => ['api_database', 'customer_database'],
```

### 4. CI-specific optimizations

- **MariaDB tmpfs:** Mount data dir on RAM disk for zero I/O latency
- **Shared DB prep:** One CI job prepares DB, test jobs clone from it
- **Cache test DBs:** Skip re-migration if migration files haven't changed
- **Separate suites:** Run no-DB tests (Unit) on cheaper runners

## Related project docs

- `agents/reference/docs/seeders.md` — seeder conventions (if exists)

## Output format

1. Optimized test configuration or seeder with timing comparison
2. Parallelization or caching improvements applied

## Gotcha

- Don't use RefreshDatabase when DatabaseTransactions suffices — full refresh is 10x slower.
- The model forgets that parallel tests share the database — use unique identifiers in test data.
- Seeder optimization has the highest ROI — a 2s seeder running 100 times = 200s wasted.
- Don't add indexes to test databases just for test performance — the real fix is better test design.


## Do NOT

- Do NOT use RefreshDatabase when DatabaseTransactions works — 10x slower.
- Do NOT run full test suite on every code change — use `--filter`.
- Do NOT add test-only indexes — fix test design instead.
- Do NOT disable parallel testing to "fix" flaky tests — fix the root cause.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…