Testing Laravel Made Easy with Pest: A Beginner's Guide with Code Examples

Updated:

Laravel is a popular PHP web application framework that provides an elegant and convenient way to build web applications. It comes with a built-in testing framework that enables developers to write and run tests to ensure that their application is working as expected. However, writing tests can be a tedious and time-consuming task, especially when you have to deal with verbose and repetitive syntax.

Pest is a relatively new testing framework for PHP that provides an expressive, simple, and intuitive syntax for writing tests (v2 has just been announced). It's built on top of PHPUnit and supports all its features while adding its own set of features and improvements. In this blog post, we'll explore how to use Pest to test Laravel applications.

Installing Pest

Before we dive into writing tests, let's install Pest. Pest can be installed using Composer, the PHP dependency manager, as follows:

composer require pestphp/pest --dev

This will install Pest and its dependencies as development dependencies in your app.

Writing tests with Pest

Pest provides a simple and expressive syntax for writing tests. Tests are written as functions that describe what the test does and what is expected. Here's an example of a simple test using Pest:

test('it should add two numbers', function () {
$sum = 1 + 1;
 
expect($sum)->toEqual(2);
});

In this test, we're describing what the test does in the test name, which is a string passed as the first argument to the test function. We're then performing the test logic inside the function, which in this case is adding two numbers and assigning the result to the $sum variable. Finally, we're using the expect function to assert that the $sum variable is equal to 2 using the toEqual matcher.

Let's continue seeing how we can use Pest to test Laravel...

Testing a Laravel Controller

Let's say we have a controller that retrieves a list of users and returns it as a JSON response. Here's the controller code:

namespace App\Http\Controllers;
 
use App\Models\User;
use Illuminate\Http\Request;
 
class UserController extends Controller
{
public function index(Request $request)
{
$users = User::all();
 
return response()->json($users);
}
}

To test this controller using Pest, we'll create a new test file in the tests directory named UserControllerTest.php. Here's how the test file should look like:

<?php
 
test('it should return a list of users', function () {
$response = $this->get('/users');
 
$response->assertOk();
$response->assertJsonCount(User::count());
});

In this test, we're sending a GET request to the /users endpoint using the $this->get() helper function provided by Pest. We're then asserting that the response status code is 200 using the assertOk() method provided by Laravel. Finally, we're asserting that the response JSON contains the correct number of users using the assertJsonCount() method provided by Laravel.

Note that we're not using the traditional Laravel test case class that extends TestCase. Instead, we're using Pest's own test helpers that provide a simpler and more expressive syntax.

To make this test work, we need to define the /users route in our Laravel application. We can do this by adding the following code to the routes/web.php file:

use App\Http\Controllers\UserController;
 
Route::get('/users', [UserController::class, 'index']);

Now we're ready to run the test using the pest command:

./vendor/bin/pest

This will run all the tests in the tests directory and output the results.

Testing a Laravel Model

Let's say we have a model named User that represents a user in our application. Here's the model code:

namespace App\Models;
 
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
 
class User extends Model
{
use HasFactory;
 
protected $fillable = [
'name',
'email',
'password',
];
}

To test this model using Pest, we'll create a new test file in the tests directory named UserTest.php. Here's how the test file should look like:

<?php
 
use App\Models\User;
 
test('it should create a new user', function () {
$user = User::factory()->create([
'name' => 'John Doe',
'email' => 'john@example.com',
'password' => bcrypt('password'),
]);
 
expect($user->name)->toBe('John Doe');
expect($user->email)->toBe('john@example.com');
expect(password_verify('password', $user->password))->toBeTrue();
});

In this test, we're using Laravel's model factories to create a new user with the specified attributes. We're then using Pest's expect function to assert that the user has the correct attributes.

Note that we're not using the traditional Laravel test case class that extends TestCase. Instead, we're using Pest's own test helpers that provide a simpler and more expressive syntax.

To make this test work, we need to define the UserFactory class that generates the user attributes. We can do this by creating a new file named UserFactory.php in the database/factories directory and adding the following code:

<?php
 
namespace Database\Factories;
 
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Facades\Hash;
 
class UserFactory extends Factory
{
protected $model = User::class;
 
public function definition()
{
return [
'name' => $this->faker->name(),
'email' => $this->faker->unique()->safeEmail(),
'password' => Hash::make('password'),
];
}
}

This will define the UserFactory class that generates random user attributes using the Faker library and the Hash facade to hash the password.

Now we're ready to run the test using the pest command:

./vendor/bin/pest

As you can see, Pest is a powerful and intuitive testing framework that provides a simple and expressive syntax for writing tests in PHP. It works seamlessly with Laravel and provides a cleaner and more readable way to write tests. By using Pest, you can write tests faster, with less boilerplate code, and with better readability.

Join the conversation here on Twitter.