jasonmccreary/laravel-test-assertions
Adds a trait of extra PHPUnit assertions for Laravel testing. Confirm controllers/actions and named routes use specific FormRequest validation or middleware, compare validation rules (subset or exact), check rule instances, and assert view data is explicitly null.
## Getting Started
### Minimal Setup
1. **Installation**
```bash
composer require --dev jasonmccreary/laravel-test-assertions
No additional configuration is required—works out-of-the-box with Laravel’s built-in testing tools.
use JasonMcCreary\LaravelTestAssertions\Assertions;
/** @test */
public function user_can_access_dashboard()
{
$response = $this->get('/dashboard');
Assertions::assertOk($response)
->assertSee('Welcome')
->assertDontSee('Unauthorized');
}
Assertions facade.Chaining Assertions Use method chaining for readability:
Assertions::assertCreated($response)
->assertJsonStructure(['data' => ['id', 'name']])
->assertJsonFragment(['name' => 'John Doe']);
Testing Redirects
$response = $this->post('/login', ['email' => 'test@example.com']);
Assertions::assertRedirect($response)
->assertRedirectToRoute('dashboard');
Database Assertions
$this->post('/users', ['name' => 'Alice']);
Assertions::assertDatabaseHas('users', ['name' => 'Alice'])
->assertDatabaseMissing('users', ['name' => 'Bob']);
Exception Testing
$this->expectException(UnauthorizedException::class);
$response = $this->get('/admin');
Assertions::assertForbidden($response);
Custom Assertions Extend the facade for project-specific logic:
use JasonMcCreary\LaravelTestAssertions\Assertions as BaseAssertions;
class CustomAssertions extends BaseAssertions {
public static function assertValidated($response, array $rules) {
// Custom logic
}
}
HttpTests, FeatureTests, and UnitTests.test('user creation', function () {
$response = $this->post('/users', ['name' => 'Alice']);
Assertions::assertCreated($response)->assertJson(['name' => 'Alice']);
});
Over-Chaining Avoid excessive chaining for complex assertions—break into smaller tests or helper methods for clarity.
// Bad: Too nested
Assertions::assertOk($response)->assertSee('...')->assertDontSee('...')->assertJson(...);
// Good: Split into steps
Assertions::assertOk($response);
Assertions::assertSee($response, 'Welcome');
Database Assertions in Transactions
If using database transactions (e.g., refreshDatabase()), ensure assertions run after the transaction commits:
$this->actingAs($user)->post('/posts');
$this->assertDatabaseHas('posts', ['title' => 'Test']); // Runs in transaction
Mocking Side Effects
Some assertions (e.g., assertDatabaseHas) may not work with mocked Eloquent models. Use real models or DatabaseMigrations trait.
Response vs. View Assertions
assertSee() works on response content, not Blade views directly. For views, use:
$this->view()->assertSee('Welcome');
dd($response->getContent()) to inspect raw response content.php artisan migrate:fresh --seed
Custom Assertion Methods
Extend the Assertions class to add project-specific logic:
class AppAssertions extends JasonMcCreary\LaravelTestAssertions\Assertions {
public static function assertApiSuccess($response) {
return static::assertOk($response)
->assertJsonStructure(['data', 'meta']);
}
}
Override Default Behavior
Publish the package’s config (if available) or monkey-patch the Assertions class:
JasonMcCreary\LaravelTestAssertions\Assertions::macro('customAssert', function ($response) {
// Logic
});
Testing API Responses
For APIs, combine with assertJson() for stricter validation:
Assertions::assertOk($response)
->assertJsonCount(1, 'data')
->assertJsonFragment(['status' => 'active']);
assertSoftDeletes for soft-deleted models:
Assertions::assertSoftDeleted('users', ['name' => 'Deleted User']);
assertDatabaseHas) in test setups.expectExceptionObject() alongside this package.app()->bind() in tests) while using this package for assertions.
NO_UPDATE_NEEDED would not apply here—this is the updated assessment reflecting the new release.
How can I help you explore Laravel packages today?