Weave 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

Phpunit Skeleton Generator Laravel Package

phpunit/phpunit-skeleton-generator

PHPUnit Skeleton Generator creates skeleton test classes from existing production code and skeleton class stubs from test cases, helping PHP developers bootstrap PHPUnit tests quickly with less boilerplate.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

What the package is. phpunit/phpunit-skeleton-generator is a dev-only CLI utility (phpunit-skelgen) that reads a production class via reflection and emits a PHPUnit test class skeleton — @covers annotation, one stub method per public method, bodies marked incomplete. It also works in reverse (production class skeleton from a test). It ships no runtime code, no service provider, and nothing that belongs in require rather than require-dev.

Architecture fit. Conceptually it fits as a scaffolding tool in the developer-workstation layer, not the application architecture. In a Laravel codebase the fit is materially weaker than the description implies: generated classes extend PHPUnit\Framework\TestCase directly, not Tests\TestCase, so every output needs manual rebasing before it can use RefreshDatabase, factories, actingAs, or HTTP assertions. The generator has no concept of controllers, form requests, jobs, events, or container bindings, which is where most Laravel test-writing effort actually lives. Realistic value is confined to plain unit-testable classes: value objects, services, actions, DTOs, small domain helpers. For anything Feature-level it produces a stub that has to be rewritten.

Integration feasibility. This is the blocking issue. The final 2.x line targets PHP ^7.0 and PHPUnit ^6.0, which is long EOL. A modern Laravel 10/11 application on PHPUnit 10/11 cannot co-install it — Composer will refuse to resolve, or will attempt to downgrade PHPUnit, which is unacceptable. Workarounds are narrow:

  • Install globally or in an isolated tools directory so its constraints never touch the project lockfile, then point it at the app's autoloader via the bootstrap option.
  • Fork and relax the constraint — but the generator's AST/reflection assumptions are PHP 7-era; typed properties, enums, readonly, attributes, union/intersection types, and first-class callables are not modelled, so a fork is a rewrite of the interesting parts, not a version bump.
  • No maintained PHAR/distribution channel to sidestep the dependency graph.

Technical risk. High, and skewed toward silent failure rather than loud failure:

  • Abandoned upstream. Zero dependents and a zero score are the market's verdict. No security response process, no PHP 8 compatibility, no issue triage.
  • Reflection requires loading production code. The tool must autoload the target class and resolve its type hints in a CLI process. Any class with bootstrapping side effects, env dependencies, or heavy constructor-time dependencies becomes a generation-time fatal error that has nothing to do with the code being tested.
  • False coverage signal. Every generated method is markTestIncomplete. If these land in CI and nobody finishes them, you ship green builds and an inflated test count with zero assertions. This is the single most likely way the tool causes harm.
  • Supply-chain surface is limited by being dev-only, but an unmaintained package in require-dev still runs arbitrary code on developer machines and CI runners.

Key questions to answer before spending any time on it:

  1. What percentage of our test-writing time actually goes to unit-testable classes versus Feature/HTTP/queue/console tests? If the latter dominates, the tool addresses a minority of the problem.
  2. Are we on PHPUnit 10/11 today, and is downgrading even on the table? (Almost certainly not.)
  3. Is the real ask "generate tests" or "enforce a test-file convention"? The second is solved by a template and a lint rule.
  4. Does the team already have IDE-level generation (PhpStorm generate-test, artisan make:test, Pest's pest:test) that covers 80% of this with zero dependency cost?
  5. Would we accept owning a fork indefinitely, including PHP 8.4+ syntax?

Integration Approach

Stack fit. Poor-to-marginal for a standard Laravel stack. The relevant comparison set: php artisan make:test --unit, pest:test, IDE generation, and a checked-in stubs/ template directory. Those are zero-dependency, framework-aware, and already produce the correct base class and namespace. The generator's only edge is auto-enumerating public methods and emitting @covers per method — a ~40-line internal script or a code template with a method loop reproduces it, and we control it.

Migration path. Do not add it to composer.json. Ranked options:

  1. Preferred — replace, don't migrate. Ship a house test stub (correct base class, RefreshDatabase for Feature, namespace inferred from path) plus a short internal generator command. Cost is days, not weeks; payoff is the same and the artifact is maintainable.
  2. Tolerated — isolated ad-hoc tooling. composer global require or a tools/skelgen/composer.json sandbox purely for one-off unit skeletons on plain classes, invoked manually, never wired into make or CI. Keeps the abandoned constraint out of the app lockfile.
  3. Discouraged — fork and pin. Only justified if we have a concrete, measured need and someone who will own the parser updates through PHP version churn.

Compatibility checklist for whichever route is chosen:

  • PHP version floor vs. generator's PHP 7 assumptions.
  • PHPUnit API surface — TestCase, @covers semantics changed in PHPUnit 10/11 (metadata via attributes, @covers deprecations).
  • Laravel test base class and trait bootstrapping (CreatesApplication, RefreshDatabase, WithoutMiddleware).
  • PSR-4 mapping: does the output namespace and file path match composer.json autoload-dev, or does it need manual fixing every time?
  • Does it overwrite existing test files, or refuse? Confirm before pointing it at a real tree.

Sequencing if we pilot anyway:

  1. Sandbox install in an isolated tools directory; no changes to the app lockfile.
  2. Run against three representative unit-testable classes; time the generate-plus-fix cycle end to end.
  3. Measure the delta against make:test + hand-editing. If the fix-up time exceeds the typing it saved, stop.
  4. Only if step 3 is favorable, decide between the internal-script route and a fork. Do not standardize on the upstream package.

Operational Impact

Maintenance. Effectively zero upstream. There is no release cadence to track because there are no releases. Every PHP or PHPUnit upgrade becomes our problem. The true cost is not the install — it is the fork debt if we go route 3 above.

Support. No maintainer triage, no documented support channel, no CVE process. Any breakage is diagnosed by whoever adopted it. For a dev-only tool that is survivable; for anything referenced from CI templates or onboarding docs it becomes a recurring interruption.

Scaling. Invocation cost is trivial (single-process CLI, one class at a time). The scaling problem is organizational: the tool works fine for one engineer on one machine and degrades badly as a standard, because every developer must independently remember the base-class rewrite, the namespace fix, and the fact that generated tests are empty. That knowledge does not survive onboarding.

Failure modes to plan for:

  • Silent coverage inflation — incomplete tests counted as tests. Mitigate with a coverage gate that measures line/assertion coverage, never test counts, and a CI check that fails on markTestIncomplete in new files.
  • Autoload side effects — generation-time fatals from classes with real dependencies. Mitigate by restricting use to dependency-free classes.
  • Class/file drift — generated skeletons for methods that were renamed or deleted, discovered months later.
  • Overwrite conflicts on re-run against existing test files; verify behavior before any batch operation.
  • Lockfile corruption — the realistic worst case is someone "just installing" it into the project and Composer resolving to an old PHPUnit, quietly downgrading the suite. A conflict guard in composer.json is cheap insurance regardless of the decision.

Ramp-up. Low for an individual (one README read), high for a team (must teach base-class rebasing, namespace correction, and the discipline of finishing stubs). Ramp-up cost exceeds benefit at team scale.

Bottom line: do not adopt. The capability is real but thin, the package is abandoned and dependency-incompatible with any current Laravel/PHPUnit stack, and the same outcome is available from artisan make:test, IDE generation, or a few days of internal tooling that we would own outright. The zero dependents and zero score are consistent with what the code inspection shows — this is a historical artifact, not a component. Recommended action: decline the dependency, run a two-day spike on a house test-stub generator, and revisit only if that spike fails.

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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons