Introduction to Testing in Laravel
Testing is a critical aspect of software development that ensures your application works as intended. Laravel provides a robust testing suite out of the box with PHPUnit, a popular testing framework for PHP. This guide will walk you through setting up and running tests in Laravel, explaining the differences between unit and feature tests, and providing examples for various testing scenarios.
Folder Structure: Unit vs. Feature Tests
In Laravel, tests are typically organized into two main directories: Unit and Feature.
Unit Tests: These tests are designed to test small, isolated parts of your application, such as individual methods or classes. They are usually located in the tests/Unit directory. Each test function should start with the word test.
Example:
public function testExampleFunction() {
$this->assertTrue(true);
}
Feature Tests: These tests handle more complex interactions and typically test several components working together. They are located in the tests/Feature directory. Feature tests often involve making HTTP requests and checking responses.
Running Tests in Laravel
To run all tests in your Laravel application, use the following command:
./vendor/bin/phpunit
Configuring the Testing Environment
Before running tests, it's important to configure your testing environment. Modify your phpunit.xml file to set environment variables for testing. For example, to use an SQLite in-memory database for faster tests:
<php>
<env name="APP_ENV" value="testing"/>
<env name="APP_MAINTENANCE_DRIVER" value="file"/>
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="CACHE_STORE" value="array"/>
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>
<env name="MAIL_MAILER" value="array"/>
<env name="PULSE_ENABLED" value="false"/>
<env name="QUEUE_CONNECTION" value="sync"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="TELESCOPE_ENABLED" value="false"/>
</php>
After enabling SQLite as your testing environment, clear the configuration cache:
php artisan config:clear
*Example: Testing if Profile Route Exists and Works Correctly
*
Create a test for the profile route:
php artisan make:test ProfileTest
Add a test method to check if the profile page displays specific text:
public function testProfilePage(){
$response = $this->get('/profile');
$response->assertSeeText('Your Profile');
}
Testing Database Interactions
Setting Up a Testing Database
Before testing database interactions, create a testing database configuration in config/database.php:
'mysqltesting' => [
'driver' => 'mysql',
'url' => env('DB_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => 'laravel_testing',
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
Running Database Tests
Run the PHPUnit command to ensure the test database is created and working:
./vendor/bin/phpunit
Example: Testing User Registration
Create a test for user registration:
php artisan make:test UserTest
Add a test method to verify a user can be created and saved to the database:
public function test_registration(): void
{
$user = new User();
$user->name = 'Test User';
$user->email = 'email@example.com';
$user->password = bcrypt('password');
$user->save();
$this->assertDatabaseHas('users', ['email' => 'email@example.com']);
}
Testing Store Action
Create a test for the store action in the PostTest class:
public function testPostStoreValid()
{
$data = [
'title'=> 'Test Post',
'slug' => 'test-post',
'content' => 'Content of the post',
'active' => true,
];
$this->post('/posts', $data)
->assertStatus(302)
->assertSessionHas('status');
$this->assertEquals(session('status'), 'Post was created!');
}
Testing for Failure
Add a test method to check for validation errors:
public function testPostFail()
{
$data = [
'title'=> '',
'content' => '',
];
$this->post('/posts', $data)
->assertStatus(302)
->assertSessionHas('errors');
$messages = session('errors')->getMessages();
$this->assertEquals($messages['title'][0], 'The title must be at least 4 characters.');
$this->assertEquals($messages['title'][1], 'The title field is required.');
$this->assertEquals($messages['content'][0], 'The content field is required.');
}
*Testing Update Action
*
Add a test method for updating a post:
public function testPostUpdate()
{
$post = new Post();
$post->title = "Initial Title";
$post->slug = Str::slug($post->title, '-');
$post->content = "Initial content";
$post->active = true;
$post->save();
$this->assertDatabaseHas('posts', $post->toArray());
$data = [
'title' => 'Updated Title',
'slug' => 'updated-title',
'content' => 'Updated content',
'active' => false,
];
$this->put("/posts/{$post->id}", $data)
->assertStatus(302)
->assertSessionHas('status');
$this->assertDatabaseHas('posts', ['title' => $data['title']]);
$this->assertDatabaseMissing('posts', ['title' => $post->title]);
}
Testing Delete Action
Add a test method for deleting a post:
public function testPostDelete()
{
$post = new Post();
$post->title = "Title to delete";
$post->slug = Str::slug($post->title, '-');
$post->content = "Content to delete";
$post->active = true;
$post->save();
$this->assertDatabaseHas('posts', $post->toArray());
$this->delete("/posts/{$post->id}")
->assertStatus(302)
->assertSessionHas('status');
$this->assertDatabaseMissing('posts', $post->toArray());
}
**
Running Specific Tests with PHPUnit
**
To run a specific test method or class, use the --filter option with PHPUnit. Here are some examples:
Run a Specific Test Method
./vendor/bin/phpunit --filter PostTest::testPostDelete
Run All Tests in a Specific Class
./vendor/bin/phpunit --filter PostTest
Run Tests in a Specific File
./vendor/bin/phpunit tests/Feature/PostTest.php
Verbose Output
For more detailed output, add the -v option:
./vendor/bin/phpunit --filter PostTest::testPostDelete -v
Top comments (0)