Working with Pest in Laravel Zero

September 1, 2020

Pest is a progressive PHP testing framework by Nuno Maduro. Behind the scenes it uses PHPUnit, and it provides an expressive, enjoyable syntax for writing tests. Pest is similar to the JavaScript Jest framework in the way that it is written.

For reference, the Laravel Zero 8 framework test suite was updated to use Pest.
See the following PRs for details on the changes: #400, #403.

Installation

Pest is very quick to get started with for Laravel Zero 8, by following the installation documentation. Note that Pest requires PHP 7.3 or later, and PHPUnit 9.3, which are the defaults in Laravel Zero 8.

Once Pest has been installed, your existing tests can be run with ./vendor/bin/pest (or .\vendor\bin\pest on Windows).

As with the Laravel installation process, it's worth creating a tests/Pest.php file and adding a uses() statement. This will usually be to extend your Tests\TestCase class as follows:

uses(Tests\TestCase::class)->in(__DIR__);

Additionally, if you would like access to test generation and other Pest commands, you can add the following service provider to your app.providers configuration:

// config/app.php

return [
  // ...
  'providers' => [
      // Existing providers ...
      Pest\Laravel\PestServiceProvider::class,
  ],
];

This will allow you to use the following useful commands:

  • Generate a new feature test:
    php <application> pest:test [name]
  • Generate a new unit test:
    php <application> pest:test --unit [name]
  • Generate a new dataset:
    php <application> pest:dataset [name]

Helper functions

Pest allows for a feature known as "helpers", these are useful functions that are saved in the tests/Helpers.php file. Here are two useful helpers for working in Laravel Zero that wrap methods on the TestCase:

if (! function_exists('assertCommandCalled')) {
    function assertCommandCalled(string $command, array $arguments = []): void
    {
        test()->assertCommandCalled($command, $arguments);
    }
}

if (! function_exists('assertCommandNotCalled')) {
    function assertCommandCalled(string $command, array $arguments = []): void
    {
        test()->assertCommandNotCalled($command, $arguments);
    }
}

In Pest 0.3 and later, all global helpers can be called on the instance as a method for higher-order tests.

Writing tests

The best way to learn about writing tests in Pest is from the documentation, but for a quick overview you can create tests as follows:

// Normal test syntax
test('it can assert true is true', function () {
   expect(true)->toBeTrue();
});

// Higher order test syntax
test('it can assert true is true in higher order syntax')->assertTrue(true);

Console output

Pest provides a clean output when you run your test suite as shown below.

Example Pest test output

When a test passes successfully, Pest will output a tick next to the test name. When a test fails, it will display a cross, and thanks to Collision the error message and a stack trace of where the error was thrown will be shown at the bottom of the test output. This allows quick debugging of tests and makes it much faster to find what is failing in a test.

Final remarks

As Pest is a "progressive" testing framework, its tests can be executed alongside class-based PHPUnit tests. This is great for situations where you are transitioning to the Pest syntax, or if you only want a subset of your tests to use the Pest syntax.