Fuzz Testing in Pest 5 for Laravel Developers | Mohamed Said       [Skip to content](#main)  [ ![](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png) Mohamed SaidLaravel Backend Engineer ](https://www.msaied.com/public) - [Home](https://www.msaied.com/public)
- [Projects](https://www.msaied.com/public/projects)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [About](https://www.msaied.com/public#about)

           [  Contact](https://www.msaied.com/public#contact) Menu 

Menu
----

Close 

 - [HomeStart here](https://www.msaied.com/public)
- [ProjectsCase studies](https://www.msaied.com/public/projects)
- [ArticlesEngineering notes](https://www.msaied.com/public/articles)
- [CertificatesCredentials](https://www.msaied.com/public/certificates)
- [AboutHow I work](https://www.msaied.com/public#about)
- [ContactGet in touch](https://www.msaied.com/public#contact)

  [Start a conversation](https://www.msaied.com/public#contact) [WhatsApp](https://wa.me/201094619204) [Email](mailto:hello@msaied.com) 

 1. [Home](https://www.msaied.com/public)
2. /
3. [Articles](https://www.msaied.com/public/articles)
4. /
5. [Composer Pacakge](https://www.msaied.com/public/articles?category=composer-pacakge)
6. /
7. Find Unexpected Test Inputs with Fuzz for Pest

   [Composer Pacakge](https://www.msaied.com/public/articles?category=composer-pacakge) [PHP](https://www.msaied.com/public/articles?category=php) 

 Find Unexpected Test Inputs with Fuzz for Pest
===============================================

 Fuzz is a Pest 5 package that brings coverage-guided fuzz testing to Laravel and PHP projects. It generates and mutates string inputs automatically, surfacing crashes and edge cases your hand-written tests would never reach.

 ![](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp) [Mohamed Said](https://www.msaied.com/public#person) Published 7 Sep 2026 · Updated 8 Sep 2026 · 4 min read

ShareCopy linkCopied

 ![Find Unexpected Test Inputs with Fuzz for Pest](https://cdn.msaied.com/644/a8804395d4fd322b55d91a7dd9e6ffa3.png) 

  On this page +1. [What Is Fuzz Testing?](#what-is-fuzz-testing)
2. [How Coverage-Guided Fuzzing Works](#how-coverage-guided-fuzzing-works)
3. [Installation](#installation)
4. [A Practical Example](#a-practical-example)
5. [What Fuzz Found](#what-fuzz-found)
6. [What the Test Actually Checks](#what-the-test-actually-checks)
7. [Fitting Fuzz Into Your Workflow](#fitting-fuzz-into-your-workflow)
8. [Key Takeaways](#key-takeaways)

 What Is Fuzz Testing?
---------------------

A conventional test suite covers the cases you think of: a valid string, an empty one, maybe a boundary value. Fuzz testing takes a different approach — it generates and mutates inputs automatically, then passes them to your code looking for failures you never anticipated.

[Fuzz](https://github.com/JonPurvis/fuzz), a package by Jon Purvis, brings this technique directly into [Pest 5](https://laravel-news.com/pest-5) tests. Under the hood it uses nikic's PHP-Fuzzer to mutate strings and report any failures through Pest's familiar output.

How Coverage-Guided Fuzzing Works
---------------------------------

A basic fuzzer mutates an input — adding, removing, or replacing characters — and runs your code with the result. A **coverage-guided** fuzzer goes further: it watches which code paths each input exercises. When a mutated input reaches a previously unexplored branch, the fuzzer saves it to a **corpus** and uses it as the basis for further mutations.

This matters for code with successive validation steps. Once an input passes the first check, the fuzzer can focus on mutating strings that reach the second check, and so on. PHP-Fuzzer tracks transitions between PHP code blocks to collect this feedback. Fuzz handles the instrumentation for you — no Xdebug or `--coverage` flag required.

Installation
------------

Fuzz requires PHP 8.4+ and Pest 5. Install it as a dev dependency:

```bash
composer require jonpurvis/fuzz --dev

```

A Practical Example
-------------------

Consider a helper that parses a rate-limit spec like `100/60s` into requests per second:

```php
namespace App;

final class RateLimit
{
    public static function perSecond(string $spec): float
    {
        $parts  = explode('/', $spec);
        $count  = (int) $parts[0];
        $window = (int) rtrim($parts[1] ?? '1s', 's');

        return $count / $window;
    }
}

```

The helper does no input validation. A fuzz test can probe it for crashes:

```php
use App\RateLimit;
use function Fuzz\fuzz;

$target = static function (string $input): void {
    RateLimit::perSecond($input);
};

test('rate limit spec parser never fatals', function () use ($target): void {
    fuzz($target)
        ->seed(['100/60s', '5/1s', '1000/3600s'])
        ->withDictionary(['/', 's', '0', '1'])
        ->runs(2000)
        ->maxLen(16)
        ->run('rate-limit-parser');
});

```

- `seed()` — starting examples the fuzzer mutates from.
- `withDictionary()` — fragments the fuzzer may insert (does not restrict other characters).
- `runs()` — total mutation budget.
- `maxLen()` — maximum byte length of generated strings.
- `run()` — unique name used to separate corpus and crash files.

**Important:** define `$target` outside `test()`. Fuzz runs the closure in a separate PHP process where Pest's generated test class is unavailable; keeping it outside avoids that dependency and ensures coverage is recorded correctly.

### What Fuzz Found

In a test run, Fuzz produced the input `5/`. The missing window segment becomes an empty string, PHP casts it to `0`, and dividing by zero throws a `DivisionByZeroError`. Pest reports the test as failed. The crashing input is saved under `.pest/fuzz-crashes/` so you can reproduce and fix it.

What the Test Actually Checks
-----------------------------

By default, Fuzz fails on `TypeError`, unsuppressed PHP warnings and notices, and division-by-zero errors. Ordinary exceptions — including Laravel validation exceptions — are ignored unless you use the `allow()` method to opt specific exception types in.

To catch wrong return values as well as crashes, add a Pest expectation inside the target closure. For example, an encode/decode round-trip test could assert that decoding an encoded string always returns the original value.

A per-input timeout is available via `timeout()`, which requires the `pcntl` extension.

Fitting Fuzz Into Your Workflow
-------------------------------

Fuzz complements, rather than replaces, your regular tests and datasets. Use it when code accepts a wide range of possible inputs — parsers, format converters, user-supplied text handlers — where listing every edge case by hand is impractical.

- Keep a small run budget (`runs`) in your normal test suite for fast feedback.
- Run a larger budget in a scheduled CI job for deeper exploration.
- After fixing a crash, add the failing input to a named dataset so regression is caught by ordinary tests.

### Key Takeaways

- Fuzz for Pest wraps PHP-Fuzzer with a clean Pest 5 API.
- Coverage-guided mutation finds inputs that reach new code branches automatically.
- No Xdebug or `--coverage` flag needed — instrumentation is built in.
- Failing inputs are saved to `.pest/fuzz-crashes/` for easy reproduction.
- Define the target closure outside `test()` to ensure coverage recording works.
- Combine fuzz tests with conventional datasets for complete coverage.

---

*Source: [Find Unexpected Test Inputs with Fuzz for Pest — Laravel News](https://laravel-news.com/pest-fuzz)*

- [Pest](https://www.msaied.com/public/articles?search=Pest)
- [Fuzz Testing](https://www.msaied.com/public/articles?search=Fuzz%20Testing)
- [Laravel Testing](https://www.msaied.com/public/articles?search=Laravel%20Testing)
- [PHP](https://www.msaied.com/public/articles?search=PHP)
- [Package](https://www.msaied.com/public/articles?search=Package)

 Frequently asked questions 
---------------------------

  What PHP and Pest versions does the Fuzz package require?Fuzz requires PHP 8.4 or higher and Pest 5. Install it as a dev dependency with `composer require jonpurvis/fuzz --dev`.

   Why should the fuzz target closure be defined outside the `test()` block?Fuzz runs the closure in a separate PHP process where Pest's generated test class is not available. Defining the closure outside `test()` avoids that dependency and ensures coverage is recorded correctly by PHP-Fuzzer.

   What kinds of failures does Fuzz detect by default?By default, Fuzz reports TypeError, unsuppressed PHP warnings and notices, and errors such as DivisionByZeroError. Ordinary exceptions, including Laravel validation exceptions, are ignored unless you explicitly opt them in with the `allow()` method.

   ![Mohamed Said](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp)About the author
----------------

[Mohamed Said](https://www.msaied.com/public#person)Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

[About](https://www.msaied.com/public#about) [GitHub ↗](https://github.com/EG-Mohamed) [LinkedIn ↗](https://www.linkedin.com/in/msaiedm/) [WhatsApp ↗](https://wa.me/201094619204) [Email Address ↗](mailto:hello@msaied.com) [My CV ↗](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)  

   [Previous articleLaravel Rulebook: Manage Business Rules That Change by Date](https://www.msaied.com/public/articles/laravel-rulebook-manage-business-rules-that-change-by-date) [Next articleContextual Binding and Method Injection in Laravel's Service Container](https://www.msaied.com/public/articles/contextual-binding-and-method-injection-in-laravels-service-container-3)  

   On this page
-------------

1. [What Is Fuzz Testing?](#what-is-fuzz-testing)
2. [How Coverage-Guided Fuzzing Works](#how-coverage-guided-fuzzing-works)
3. [Installation](#installation)
4. [A Practical Example](#a-practical-example)
5. [What Fuzz Found](#what-fuzz-found)
6. [What the Test Actually Checks](#what-the-test-actually-checks)
7. [Fitting Fuzz Into Your Workflow](#fitting-fuzz-into-your-workflow)
8. [Key Takeaways](#key-takeaways)

 ###  Have a technical challenge?

 Tell me what you’re building. I reply within two working days.

[Start a conversation](https://www.msaied.com/public#contact) 

   Related articles
-----------------

 [ ![](https://cdn.msaied.com/740/cce86edc21eddcbdd2f2454fadaf9c70.png)  · 3 min read### The Pipeline Pattern in Laravel: Custom Pipelines Beyond Middleware

5 Oct 2026 ](https://www.msaied.com/public/articles/the-pipeline-pattern-in-laravel-custom-pipelines-beyond-middleware-1) [ ![](https://cdn.msaied.com/739/2d6897fdcdcf090613f96f72a64b8a78.png)  · 4 min read### MySQL Full-Text Search in Laravel: Indexes, Relevance Scoring, and Boolean Mode

4 Oct 2026 ](https://www.msaied.com/public/articles/mysql-full-text-search-in-laravel-indexes-relevance-scoring-and-boolean-mode) [ ![](https://cdn.msaied.com/738/073696a3fefe18bec825beec5ac658f5.png)  · 4 min read### Laravel Queue Rate-Limited Middleware: Throttling Jobs Without Losing Work

4 Oct 2026 ](https://www.msaied.com/public/articles/laravel-queue-rate-limited-middleware-throttling-jobs-without-losing-work) 

  Have a technical challenge?
----------------------------

Tell me what you’re building. I reply within two working days.

 [Discuss your project ↗](https://www.msaied.com/public#contact) 

  © 2026 Mohamed Said · Built with Laravel, meant to last.Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

 - [Home](https://www.msaied.com/public)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [GitHub](https://github.com/EG-Mohamed)
- [LinkedIn](https://www.linkedin.com/in/msaiedm/)
- [WhatsApp](https://wa.me/201094619204)
- [Email Address](mailto:hello@msaied.com)
- [My CV](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
- [Sitemap](https://www.msaied.com/public/sitemap.xml)
