Testing Laravel Made Easy with Pest: A Beginner's Guide with Code Examples
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', 'password' => bcrypt('password'), ]); expect($user->name)->toBe('John Doe'); 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.