richcongress/test-tools
richcongress/test-tools is a small Laravel/PHP package offering testing helpers and utilities to simplify test setup and assertions, helping you write cleaner, more maintainable tests with less boilerplate.
1. Verify it will install before you plan around it. The package's last release is December 2021, so its composer.json constraints were written against PHP 7.x/8.0 and PHPUnit 8/9. Check first:
composer show richcongress/test-tools --all
If the constraint resolution fails on your PHP/PHPUnit version, that is your answer about adoption — do not fight it with --ignore-platform-reqs for anything beyond a throwaway evaluation branch.
2. Install as a dev dependency only.
composer require --dev richcongress/test-tools
3. Read the source, because that is the documentation. With 0 stars and a single release there is no real doc site. The first places to look, in order:
vendor/richcongress/test-tools/composer.json — the autoload / autoload-dev blocks give you the root namespace and PSR-4 layout.vendor/richcongress/test-tools/src/ — list the classes. The interesting ones are almost always named *TestCase, *Trait, or *Assert.vendor/richcongress/test-tools/tests/ — packages that ship their own suite are self-documenting; these files are your usage examples.A quick way to inventory the public surface:
grep -rn "public function\|trait \|abstract class\|interface " \
vendor/richcongress/test-tools/src
4. First use case: replace one hand-rolled block in one existing test. Pick a test that currently has the most repetitive setup — mock wiring, fixture arrays, or JSON comparisons written with assertEquals(json_encode(...)). Rewrite only that one test using a single helper from the package. Do not do a suite-wide migration on day one; you need to see the failure output quality before you commit.
5. Run it in isolation.
vendor/bin/phpunit --filter=TheRewrittenTest
The whole value proposition is "cleaner, more expressive tests," so the acceptance criterion is concrete: fewer lines and a better failure message when you deliberately break the assertion.
Wrap the package in your own base class. This is the single most important pattern given the maintenance risk. Create tests/TestCase.php that extends or uses the vendor class, and have the rest of your suite depend on your class:
namespace App\Tests;
use RichCongress\TestTools\...; // whatever the base is
abstract class TestCase extends /* vendor base */
{
// project-wide helpers, kernel boot config, etc.
}
If the package dies or breaks on a PHPUnit upgrade, you change one file instead of two hundred.
Prefer its traits over its base class where possible. Trait-based helpers compose into whatever base class your project already uses (Symfony's KernelTestCase, WebTestCase, Laravel-style bases). Extending a vendor TestCase locks you out of your framework's inheritance chain — a real problem if you're on Symfony and need KernelTestCase.
Name your factories. If the package provides mock builders or data helpers, wrap them in intention-revealing methods on your base class:
protected function aPublishedArticle(array $overrides = []): Article
{
return $this->makeArticle(['status' => 'published'] + $overrides);
}
This keeps the vendor API in one place and makes the call sites read like domain language rather than library syntax.
Use it for assertions, not for orchestration. Expressive assertions (assertJsonContains, domain-specific comparison helpers) are low-risk: they live inside a test method and fail loudly. Setup/teardown hooks and kernel lifecycle helpers are high-risk: they interact with PHPUnit's lifecycle signatures and are exactly what breaks across major versions. Adopt the former eagerly, the latter cautiously.
Integration with Symfony kernel tests. If it registers as a bundle, enable it only in the test environment (config/bundles.php under when@test, or config/packages/test/). There is no Flex recipe for a 0-star package, so you are registering it by hand. Boot the kernel once per class if the helpers support it — a kernel reboot per test is the usual cause of a suite that takes minutes instead of seconds.
Commit composer.lock and pin the version. With no dependents and one release, you are the only QA. Pin an exact version ("richcongress/test-tools": "1.x.y") and let Renovate/Dependabot surface changes rather than floating on ^1.0.
CI matrix. Because the package predates PHPUnit 10/11, run your PHP × PHPUnit matrix before merging adoption, not after. If you have no matrix, add one just for the test suite — it's the cheapest way to discover the signature incompatibility described below.
Maintenance is the dominant risk. 0 stars, 0 dependents, one release in 2021. Treat this as a vendored utility snippet with a Composer wrapper, not a strategic dependency. Budget an exit: if the base class is <300 lines, forking it into tests/Support/ and deleting the dependency is often cheaper than defending the dependency in a code review.
PHPUnit lifecycle signature breakage is the likely failure mode. Helper base classes typically implement setUp(): void, tearDown(): void, or return MockObject from factory methods. PHPUnit 10 made void return types mandatory on lifecycle hooks and changed several internal APIs. Symptom: a fatal Declaration of ... must be compatible with ... at class-load time, before any test runs. Fix by forking and adding the return types — usually a ten-minute change.
PHP 8.1/8.2 deprecations. Expect ReturnTypeWillChange warnings, implicit nullable parameter deprecations (Type $x = null), and possibly dynamic-property deprecations if the package sets undeclared properties on test doubles. These are noisy rather than fatal, but they will drown your actual test output. Suppress narrowly in phpunit.xml.dist or fix in a fork; don't globally silence deprecations.
Never let it into production autoload. require-dev only, and put your own base TestCase under autoload-dev. A stray use in a non-test class will pass locally and explode in a --no-dev deploy.
Kernel/static state causes order-dependent failures. If the helpers cache a booted kernel or container, tests that pass alone may fail in a full run. Diagnose with --order-by=random and a fixed seed; if randomization exposes failures, the helper is holding state it shouldn't. Reset it in tearDown, or fork.
Config quirks live in env vars. Test helpers that read APP_ENV or similar will behave differently between phpunit.xml.dist <env> entries, your shell, and CI. Standardize by declaring everything in phpunit.xml.dist and using force="true" where the helper reads via getenv() rather than $_ENV.
Debugging an opaque assertion failure. When an expressive assertion fails with a message you don't understand, the fastest path is to read the assertion body directly:
grep -rn -A 20 "function assert" vendor/richcongress/test-tools/src
You'll usually find it delegates to a PHPUnit assertion with a transformed message — knowing the transformation tells you what the actual mismatch was.
Extension points, in order of preference: (1) compose a trait into your own base class; (2) subclass and override protected hooks; (3) fork the single class you need. Avoid monkey-patching or reflection into private members — with an unmaintained package, that's technical debt with no upstream to fix it.
Don't let helper adoption hide intent. The failure mode of "less boilerplate" libraries is tests that become one-liners nobody can debug six months later. If a helper's name doesn't say what it asserts, wrap it in a method that does.
How can I help you explore Laravel packages today?