Skip to content
Go back

I Tried Laravel Shift's Test Generator

I ran Laravel Shift’s Test Generator on my Laravel 13 app. I already had 180 passing tests — would it fill gaps I’d missed, or just create noise?

The short answer: it generated 18 test files, I deleted 14 of them, fixed compatibility issues with the remaining 4, and ended up with 204 passing tests. Here’s exactly what happened.

Table of contents

Open Table of contents

What the Test Generator does

The Test Generator is a paid Shift that analyses your routes, controllers, and models, then generates test files. If it detects Pest in your project, it generates Pest-style tests instead of PHPUnit. It also adds helpful testing packages and attempts to generate model factories.

You give it access to your repo, it creates a branch and a pull request with all the generated files.

What it generated

Shift created 3 commits on a new branch:

  1. Added 3 Composer packagespestphp/pest-plugin-laravel, jasonmccreary/laravel-test-assertions, and laravel-shift/factory-generator
  2. Generated 18 test files — HTTP controller tests and Livewire component tests
  3. Modified TestCase.php — added JMac’s AdditionalAssertions trait

It also left 7 PR comments explaining what it did, what it couldn’t do, and what I needed to review.

What broke

Two packages were incompatible with Laravel 13

pestphp/pest-plugin-laravel v2 only supports Laravel 10-11. Running composer update failed immediately:

pestphp/pest-plugin-laravel v2.4.0 requires
laravel/framework ^10.48.9|^11.5.0
-> conflicts with your root composer.json require (^13.0)

Similarly, laravel-shift/factory-generator only supports up to Laravel 12. Both had to be removed.

This isn’t a criticism of Shift specifically — Laravel 13 is new and many packages haven’t caught up yet. But it’s worth knowing that the generator doesn’t check version compatibility before adding packages.

pest-plugin-laravel was in the wrong section

Shift added pestphp/pest-plugin-laravel to the require section (production dependencies) instead of require-dev. Testing packages should never be in production dependencies. Even if the package had been compatible, this would need fixing.

A missing import broke the entire test suite

One of the generated test files used RefreshDatabase without importing it:

<?php

uses(RefreshDatabase::class);

test('show returns an ok response', function () {
    // ...
});

Pest couldn’t find the class, and the error prevented any tests from running — not just the broken file. The fix was straightforward (my TestCase.php already applies LazilyRefreshDatabase globally, so the line was redundant), but it’s the kind of thing that would confuse someone less familiar with the test setup.

False warnings in the PR comments

Shift flagged two things that weren’t actually problems:

Pest version: It warned I was using Pest 1.x and should upgrade to Pest 2. My composer.json has "pestphp/pest": "^4.1" — I’m on Pest 4, well past the version it suggested.

12 “undefined actions”: It flagged routes like App\Livewire\Charts\FunnelLineChart@__invoke as missing controller actions. These are Livewire full-page components — they don’t have an __invoke method because Livewire handles rendering through render(). Completely normal.

What I deleted (14 of 18 files)

6 .shift.php duplicates

Where a test file already existed, Shift created a .shift.php version alongside it. I compared each pair:

Shift-generated fileExisting testVerdict
ExperimentControllerTest.shift.php2 real test scenariosExisting is better
PublicReportControllerTest.shift.php4 real test scenariosExisting is better
CreateIdeaTest.shift.php12 real test scenariosShift file was empty
TableTest.shift.php4 real test scenariosShift file was empty
IndexTest.shift.php8 real test scenariosShift file was empty
StrategyTest.shift.php10 real test scenariosShift file was empty

Four of the six .shift.php files contained only // test cases... — literally empty. The other two had a single incomplete stub that was weaker than the existing tests.

8 empty stub files

Shift generated test files for Livewire components that had no existing tests. But the generated files were all empty:

<?php

// test cases...

No test methods, no assertions, no setup. These files for CommentsTest, FunnelLineChartTest, CreateExperimentTest, SignupTest and others were just dead code.

What I kept

2 new test stubs worth completing

IdeaControllerTest.php and TeamControllerTest.php had actual test methods with route calls and assertions. Shift marked them as incomplete, but they provided a useful starting point:

test('update returns an ok response', function () {
    $this->markTestIncomplete('This test case was generated by Shift.');

    $response = $this->post(route('switch.team'), [
        // TODO: send request data
    ]);

    $response->assertRedirect(route('dashboard'));
});

jasonmccreary/laravel-test-assertions

This was the most useful addition. Jason McCreary’s test assertion package adds assertions like assertActionUsesMiddleware, assertActionUsesFormRequest, and assertRouteUsesMiddleware — things Laravel doesn’t include out of the box.

TestCase.php changes

Shift added the AdditionalAssertions trait from JMac’s package. It also confirmed the LazilyRefreshDatabase approach I was already using, which was reassuring.

The final result

After cleanup: 204 tests passing, 0 failures. The 2 incomplete stubs show as warnings, and 5 pre-existing tests remain skipped (account deletion and email verification aren’t enabled).

The questions I asked

Before running Shift, I wanted to know:

I do already have some tests, will this be an issue or is Shift purely additive?

The answer: Shift is additive. Where test files already exist, it creates .shift.php versions alongside them rather than overwriting. You’re expected to compare and merge manually.

Will there be any issues interacting with my codebase?

The main issue was private package dependencies. Shift needs to run composer install, so it requires authentication credentials for private packages like Flux Pro. You paste your auth.json contents into their encrypted credentials field.

Was it worth it?

For my codebase — with 180 existing tests and a modern Laravel 13 / Pest 4 stack — the value was limited. Most of the output needed deleting. The genuinely useful parts were:

If you’re starting from zero tests on a stable Laravel 11 or 12 app, the generator would produce more useful output. The tool is designed for that scenario — an established app that’s never had tests added. For a codebase that’s already well-tested and on the latest Laravel version, the manual cleanup outweighed the time saved.

Key takeaway

Test generators are a starting point, not a finish line. The most useful thing Shift did wasn’t the test files it generated — it was the PR comments that identified gaps in my test coverage. That list of routes without tests is worth having, even if I write those tests from scratch.


Back to top ↑