Modern Debugging and Testing in Laravel 11.44 & 12.1
Overview
Prerequisites
To follow this guide, you should be comfortable with:
- PHP8.2 or higher.
- Basic Eloquent query building and the
HTTPfacade. - Writing feature tests using PHPUnitorPest.
Key Libraries & Tools
- Laravel Framework (v11.44 / v12.1): The core framework receiving these updates.
- Guzzle HTTP: The underlying client used by Laravel's HTTP facade.
- Eloquent ORM: Laravel's database abstraction layer.
Code Walkthrough
1. Better SQL Debugging
Previously, toSql() returned statements with ? placeholders. The new getRawSql() method on query exceptions provides a fully-bound string ready for your SQL client.
try {
User::where('status', 'active')->where('id', 1)->firstOrFail();
} catch (QueryException $e) {
// Returns: select * from "users" where "status" = 'active' and "id" = 1
dump($e->getRawSql());
}
2. Recording Real HTTP Traffic
While faking is standard, sometimes you need to let a request hit a live sandbox while still asserting against it. Use HTTP::record() to capture traffic without intercepting it.
Http::record();
Http::get('https://api.github.com/users/taylorotwell');
Http::assertRecorded(function ($request, $response) {
return $request->url() === 'https://api.github.com/users/taylorotwell' &&
$response->successful();
});
3. Isolated Validation Assertions
Testing that a specific field failed while ensuring others passed used to require manual array checks. assertOnlyInvalid simplifies this logic.
$response = $this->post('/register', [
'email' => '[email protected]',
'password' => 'secret'
// 'name' is missing
]);
// Checks that 'name' failed AND email/password passed
$response->assertOnlyInvalid(['name']);
Syntax Notes
- Closure Context: In
assertRecorded, the closure provides both theRequestandResponseobjects, allowing for comprehensive integration testing. - Strictness:
assertOnlyInvalidis strict; if a field you didn't list also fails validation, the test will fail.
Practical Examples
- Performance Tuning: Use
getRawSql()in your local logging to identify poorly indexed queries that Eloquent might hide behind abstractions. - Third-Party Webhooks: Use
record()when testing integration with external APIs where you need to verify actual payload delivery to a staging environment.
Tips & Gotchas
- Internal vs External:
HTTP::record()only tracks calls made via the LaravelHttpfacade. If you instantiateGuzzleHttp\Clientdirectly, those requests stay invisible to the recorder. - JSON Response Helper: For API-only projects, use
assertOnlyJsonValidationErrorsto achieve the same isolation for JSON payloads.
