dejwcake/testing-kit
A lightweight testing toolkit for Laravel and PHP packages, offering reusable helpers, custom assertions, and setup utilities that streamline unit and integration tests. Designed for package authors, it reduces boilerplate and keeps test suites consistent and easier to maintain.
1.3.0 is an additive minor release on top of 1.2.0. No breaking changes are advertised, so pin ^1.3 and run your test suite after composer update <vendor>/<package>.
The headline feature is a single method: MocksTranslator::useRealTranslator(). It flips a test from the package's mocked translator back to Laravel's real translator and resets the validator so validation messages are resolved through the real translator too.
Where to look first:
MocksTranslator class itself (or the test case/trait that exposes it). Confirm whether the method is static, instance-level, and whether it is auto-reset between tests — the release note is one line.TestCase, since that is where the mock translator is most likely installed.First practical use case: a feature test class uses the mocked translator for speed and determinism across most cases, but one test needs the actual strings from lang/en/*.php — for example asserting a real validation message, a pluralised string, or a locale fallback. Call useRealTranslator() in that test before building the validator/request, then assert against the genuine translated output.
Default mock, opt in to real translations per test Keep the mock as the baseline for isolation and speed, and switch to the real translator only where the assertion depends on actual lang files.
public function test_registration_rejects_duplicate_email(): void
{
MocksTranslator::useRealTranslator();
$this->post('/register', ['email' => '[email protected]'])
->assertSessionHasErrors(['email' => __('validation.unique', ['attribute' => 'email'])]);
}
Switch before the validator is built Because the method "resets the validator", the useful ordering is: switch translator → make the request → assert. If you switch after a validator has already been resolved and used, you are asserting against messages produced by the mocked translator.
MocksTranslator::useRealTranslator();
$response = $this->post('/register', $payload);
$response->assertSessionHasErrors('email');
Class-level separation
Prefer splitting translator-sensitive tests into their own class or setUp() branch rather than toggling mid-test repeatedly. A class that calls useRealTranslator() in setUp() reads more clearly than one that flips per method, and it sidesteps ordering questions about whether the mock is reinstalled between tests.
protected function setUp(): void
{
parent::setUp();
MocksTranslator::useRealTranslator();
}
Pest / dataset usage
If you use Pest, call the method in beforeEach() for the file that needs real strings rather than inside each test, and verify the mock is reinstalled for the next file.
Integration with locale and fallback assertions
Real translator is the right tool when testing __(), trans_choice(), or @lang output end to end. Set the locale explicitly in the test (app()->setLocale('fr')) so the assertions do not depend on ambient config.
CI alignment The package's own suite no longer boots PostgreSQL or MariaDB. If your pipeline copied the package's service definitions, you can drop those services for this package's test job — a real if unglamorous speedup. Keep DB services for your app's own suite.
Lean installs
.gitattributes now keeps dev files (tests, AGENTS.md, CLAUDE.md, CI config) out of dist archives. That means a composer required copy is smaller, but you also cannot read those files from vendor/ in production debugging — consult the repository, not the installed package.
useRealTranslator() may still hold the mock. Rebuild the validator (or re-resolve it from the container) after switching.setUp()/tearDown() automatically. If not, a test that switches may leak state into later tests in the same process — restore explicitly or isolate the class.validation.custom_rule), which produces confusing assertion failures. Confirm the relevant lang/ files are present and that published vendor lang files are loaded.config('app.locale') and fallback_locale; the mock may not. Pin the locale in the test so the assertion is not environment-dependent.trans_choice. These are exactly the paths a mock tends to flatten. If you are writing these assertions, real translator is worth the cost — but assert the concrete string, not just "not the key".dump(get_class(app('translator'))); before and after the call settles most "why is my message still mocked" questions.vendor/. AGENTS.md, CLAUDE.md, test fixtures, and CI config are now excluded from dist archives. Use the repository for guidance.vendor:publish only if 1.3.0 documents new keys (none are mentioned).^1.3, and if you subclass or wrap MocksTranslator, re-check signatures on each minor.How can I help you explore Laravel packages today?