DEV Community

Quỳnh Nguyễn
Quỳnh Nguyễn

Posted on

I finally tried Pest for PHP & Laravel, then made the switch

I started learning pure PHP in the middle of 2015. Then, I got familiar with CodeIgniter 3 and Laravel 5.1. Through the years, Laravel is my framework of choice, and I'm still sticking with it. Such as other popular PHP projects, I see PHPUnit is the only choice for unit testing. But there was a little change in 2021 when Pest came. It's created by Nuno Maduro - an engineer at Laravel, who also makes lots of great projects/packages widely used in PHP and Laravel community.

Since the very first day of Pest, I haven't cared about it because PHPUnit is enough for me and I feel lazy to learn this new test tool. But the more Laravel community grows, the more Pest is recommended. Many Laravel projects/packages from Spatie, Livewire, Filament, ... use Pest. So the problem is when testing things related to them, I have to port to PHPUnit. I seem to have no choice. It's time for me to take a look at Pest.

The first look

Following the installation section, I create my first PHP project using Pest.

mkdir ~/Herd/lerning-pest

cd ~/Herd/learning-pest

composer require pestphp/pest --dev --with-all-dependencies

./vendor/bin/pest --init 
Enter fullscreen mode Exit fullscreen mode

The directory structure is almost the same as PHPUnit. The different thing is how a test looks. It's closure-based instead of class-based.

<?php

// tests/Unit/ExampleTest.php

test('example', function () {
    expect(true)->toBeTrue();
});
Enter fullscreen mode Exit fullscreen mode

I know using Closure that can lazily attach methods to an object in runtime. So this may be re-written in PHPUnit like that.

<?php

// tests/Unit/ExampleTest.php

class ExampleTest extends \PHPUnit\Framework\TestCase
{
    public function test_example()
    {
        $this->assertTrue(true);
    }
}
Enter fullscreen mode Exit fullscreen mode

It says Pest assertion syntax is inspired by Ruby's Rspec and Jest, which I don't know. So, I'm also not too much interested in them. For me, it doesn't matter how assertion syntax is.

I just like the result displayed when running tests. It's much prettier and cleaner than PHPUnit, I think.

Pest CLI result

Assertions

These are assertions I used the most in PHPUnit.

$this->assertSame($expected, $actual);
$this->assertTrue($condition);
$this->assertFalse($condition);
$this->assertNull($actual);
$this->assertEmpty($array);
$this->assertCount($count, $countable);
$this->assertInstanceof($type, $instance);
Enter fullscreen mode Exit fullscreen mode

They can be easily re-written in Pest.

expect($actual)->toBe($expected);
expect($condition)->toBeTrue();
expect($condition)->toBeFalse();
expect($actual)->toBeNull();
expect($actual)->toBeEmpty();
expect($actual)->toBeInstanceOf($type);
Enter fullscreen mode Exit fullscreen mode

As I mentioned earlier, Pest assertion syntax is fine, but I'm currently sticking with PHPUnit because I don't need to study new APIs. Anyway, I prefer PHPUnit assertions and only use things that are unique in Pest. Architecture Testing is an example. My test file looks like this.

<?php

test("all PHP files in LearningPest namespace must have strict mode enabled", function () {
    arch()
        ->expect('LearningPest')
        ->toUseStrictTypes();
});

test('all PHPUnit assertions are available for Pest', function () {
    $instance = new \stdClass();

    $getInstance = function () use ($instance) {
        return $instance;
    };

    $this->assertSame($instance, $getInstance());

    $this->assertInstanceOf(stdClass::class, $instance);

    $this->assertTrue(1 < 2);
    $this->assertFalse(1 > 2);

    $value = null;

    $this->assertNull($value);

    $this->assertEmpty([]);

    $array = [1, 2, 3];

    $this->assertCount(3, $array);
});
Enter fullscreen mode Exit fullscreen mode

Compulsory features

There are a number of compulsory features that allow me to work in Pest identically to PHPUnit. Here they are:

  • PHPUnit has data provider. Pest has datasets.
  • PHPUnit has setUp, tearDown, setUpBeforeClass and tearDownAfterClass. Pest has beforeEach, afterEach, beforeAll and afterAll.
  • Both have exception checks and can skip/group/filter tests.

Mockery is a standalone library, so I don't list it here.

On the other hand, Pest has lots of things may come in handy such as architecture, snapshot or stress testing and plugins. I'll discover them when writing tests.

Conclusion

  • Pest is built on top of PHPUnit, widely used and recommended in PHP and Laravel community recently.
  • Using Pest, I can work in the nearly same way before, but with prettier CLI and more helpful features.
  • Now, Pest's the default testing framework for my PHP and Laravel applications.

If you are a PHP developer who hasn't used Pest, give it a try.

Top comments (0)