A Comprehensive Guide to Testing in Laravel with PHPUnit

WBOY
Release: 2024-07-29 06:56:53
Original
717 people have browsed it

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);
}
Copy after login

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
Copy after login
Copy after login

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>
    <env name="APP_MAINTENANCE_DRIVER" value="file"></env>
    <env name="BCRYPT_ROUNDS" value="4"></env>
    <env name="CACHE_STORE" value="array"></env>
    <env name="DB_CONNECTION" value="sqlite"></env>
    <env name="DB_DATABASE" value=":memory:"></env>
    <env name="MAIL_MAILER" value="array"></env>
    <env name="PULSE_ENABLED" value="false"></env>
    <env name="QUEUE_CONNECTION" value="sync"></env>
    <env name="SESSION_DRIVER" value="array"></env>
    <env name="TELESCOPE_ENABLED" value="false"></env>
</php>
Copy after login

After enabling SQLite as your testing environment, clear the configuration cache:

php artisan config:clear

Copy after login

*Example: Testing if Profile Route Exists and Works Correctly
*

Create a test for the profile route:

php artisan make:test ProfileTest
Copy after login

Add a test method to check if the profile page displays specific text:

public function testProfilePage(){
    $response = $this->get('/profile');
    $response->assertSeeText('Your Profile');
}
Copy after login

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'),
    ]) : [],
],
Copy after login

Running Database Tests

Run the PHPUnit command to ensure the test database is created and working:

./vendor/bin/phpunit
Copy after login
Copy after login

A Comprehensive Guide to Testing in Laravel with PHPUnit

Example: Testing User Registration

Create a test for user registration:

php artisan make:test UserTest

Copy after login

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']);
}
Copy after login

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!');
}
Copy after login

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.');
}
Copy after login

*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]);
}
Copy after login

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());
}
Copy after login

**

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
Copy after login

Run All Tests in a Specific Class

./vendor/bin/phpunit --filter PostTest
Copy after login

Run Tests in a Specific File

./vendor/bin/phpunit tests/Feature/PostTest.php
Copy after login

Verbose Output

For more detailed output, add the -v option:

./vendor/bin/phpunit --filter PostTest::testPostDelete -v
Copy after login

The above is the detailed content of A Comprehensive Guide to Testing in Laravel with PHPUnit. For more information, please follow other related articles on the PHP Chinese website!

source:dev.to
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!