agentsclimarketplace

Laravel testing

Skill kwhorne/elyra-skills/skills/laravel-testing

Test Laravel applications effectively with Pest or PHPUnit - feature vs unit boundaries, factories, database strategy, what to fake, and HTTP/Livewire assertions. Use when writing tests for Laravel code, reviewing a Laravel test suite, deciding how to test a controller, job, or command, or when tests are slow or brittle.From its SKILL.md

Install
npx -y skills add kwhorne/elyra-skills --skill laravel-testing

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its file declares

Copied from the file, not written here

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

5.2 KB, ~1.2k tokens by cl100k_base, as published. Nobody here has run it

Laravel Testing

In Laravel, the feature test is the workhorse: hit the route, assert the response and the database. Unit tests are for real logic, not for ceremony.

When to use

  • Writing tests for Laravel controllers, jobs, commands, actions, or models
  • Reviewing a Laravel test suite (coverage, speed, brittleness)
  • "How should I test this?" for anything framework-coupled
  • Tests are slow, flaky, or break on every refactor

Principles

  • Test through the front door. $this->post(route(...)) exercises routing, middleware, validation, authorization, and persistence in one honest test.
  • Fake the edges, not the middle. Mail::fake(), Queue::fake(), Http::fake(), Storage::fake() — but don't mock your own repositories and services into a tautology.
  • Factories are the vocabulary. States (->suspended(), ->paid()) make tests read like specifications.
  • Each test = one behavior. Arrange, act, assert — and assert the outcome (DB row, response, dispatched job), not the implementation path.

Process

1. Choose the test type

Code under testType
Route/controller behavior, auth, validationFeature (HTTP test)
Pure logic: calculators, value objects, rulesUnit (no framework boot if possible)
Queued jobFeature-style: instantiate, handle(), assert outcomes
Artisan command$this->artisan(...)->assertExitCode(0) + DB asserts
Livewire componentLivewire::test(...) — state, actions, events, validation
Blade/UI flows across pagesFew, high-value browser tests (Dusk/Pest browser)

2. Set the database strategy

  • RefreshDatabase + SQLite :memory: for speed — unless you use DB-specific features (JSON columns, full-text, triggers); then test against the real engine, matching production
  • LazilyRefreshDatabase skips migration cost for tests that never touch the DB

3. Build with factories

$user = User::factory()->create();
$order = Order::factory()->for($user)->paid()->create();   // states > attribute soup
  • Define states in the factory for every domain status the tests mention
  • make() when persistence isn't needed; create() only when the test reads it back
  • Never seed global fixtures the whole suite shares — each test builds its own world

4. Write the feature test

it('refunds a paid order', function () {
    Queue::fake();
    $order = Order::factory()->paid()->create();

    $this->actingAs($order->user)
        ->post(route('orders.refund', $order))
        ->assertRedirect()
        ->assertSessionHas('status');

    expect($order->fresh()->status)->toBe(OrderStatus::Refunded);
    Queue::assertPushed(ProcessRefund::class, fn ($job) => $job->orderId === $order->id);
});

Cover per endpoint: happy path, validation failure (assertSessionHasErrors / assertJsonValidationErrors), authorization (wrong user → 403), and the relevant edge case. Auth tests are the ones that prevent incidents.

5. Fake the boundaries

  • Http::fake([...]) with per-URL responses; Http::assertSent(...) for contract checks; add Http::preventStrayRequests() suite-wide
  • Time: $this->travel(3)->days() / Carbon::setTestNow() for anything date-dependent
  • Event::fake() narrowly (Event::fake([OrderShipped::class])) — global fakes silence model events your code depends on

6. Keep it fast and honest

php artisan test --parallel          # paratest
php artisan test --profile           # find the slow ones
  • Suite target: minutes, not tens of minutes; single test: milliseconds unless it's a browser test
  • A test that breaks when you rename a private method tests the wrong thing — assert outcomes

Output format

## Tests: <feature/area>

**Type mix:** N feature / M unit / K browser — why.
**DB strategy:** RefreshDatabase + <engine>.

### Coverage
| Behavior | Test |
|----------|------|
| happy path | ✅ … |
| validation | ✅ … |
| authorization | ✅ … |
| <edge case> | ✅ … |

**Faked:** Queue, Http (+preventStrayRequests). **Deliberately real:** …

Anti-patterns

  • ❌ Mocking Eloquent models or your own services so the test asserts the mock, not the behavior
  • ❌ Unit-testing a controller with mocked request/response instead of one feature test
  • ❌ Skipping authorization tests — the most expensive gap in any Laravel suite
  • ❌ Shared seeders creating hidden coupling between tests
  • ❌ SQLite in tests + MySQL JSON queries in production = green suite, broken prod
  • Event::fake() globally, then wondering why observers "don't work" in tests
  • ❌ Asserting assertStatus(200) and nothing else — the page can be 200 and wrong

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 326,782. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.