Skip to content

Laravel Feature Tests Using Regex Patterns

I recently created a Laravel app that implemented swappable repositories to create random numbers.

low depth of field image of code on a monitor

I recently created a Laravel app that implemented swappable repositories to create random numbers. One of the repositories would be injected into a controller. The app is actually a tutorial/demo to show off Laravel’s Automatic Injection and random number generators seemed like an interesting way to demonstrate how to inject one particular implementation out of several. I decided to create one implementation using the standard random number generator, another using the Mersenne Twister generator, and a third using a cryptographically secure generator.

TDD Circle of Life showing three arrows, moving in a circle with headers that say Test Fails, Test Passes, and Refactor

Image via Agile in a Nutshell

I often use TDD in my process so the first test I wrote was to test for the generation of a random number. My test would drive my implementation. I created a Feature test using http-test and quickly realized that the available assertions did not contain any regex style assertions. All I wanted to do was assert that the returned content include a random number between 0 and 100. A simple pattern match on a regex of 1 to 3 digits would do nicely. But how to do this?

Laravel’s http-test capabilities are intended to make testing APIs, URLs and fixed content simple. Unfortunately, a regex pattern matching assertion is not included. To solve this shortcoming, I needed to get the actual rendered content and use PHPUnit assertions. This turned out to be quite easy since http-test tests are a superset of PHPUnit and all PHPUnit assertions are already available. This approach can be used to leverage any PHPUnit style assertion or even create a custom assertion when needed.

This example assumes a controller and route that will generate a string that includes a random number.

<?php
// app/Http/Controllers/RandomController.phpnamespace App\Http\Controllers;use Illuminate\Http\Request;class RandomController extends Controller
{
    public function index()
    {
     return sprintf("Hello and the winning number is %d!", rand(0,100));
    }
}

We need a route to invoke the controller.

<?php
// routes/web.phpRoute::get('/random', 'RandomController@index');

And finally the test.

<?php
// tests/Feature/CanMatchRegexTest.phpnamespace Tests\Feature;use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;class CanMatchRegexTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */
    public function testExample()
    {
        //$this->assertTrue(true);
        $response = $this->get('/random');        $response->assertStatus(200);
        $response->assertSeeText('Hello');        // expect content: 'Hello and the winning number is <number>!' where number is >= 0 and <= 100
        // get the actual page content
        $content = $response->getContent();
        // assert a regex
        $this->assertRegExp('/^Hello .* winning number is \d+!$/', $content);
    }
}

The rendered page is available in $response->getContent(). This can be matched using PHPUnit’s assertRegExp() assertion. You can obviously use any PHPUnit assertion or even create a more complex assertion when required.

Here’s a similar example with subtle differences. The rendered page shows a number between 0 and 100. I wanted a single assertion that verified the number to be in that range.

<?php
// tests/Feature/CanViewRandomNumberTest.phpnamespace Tests\Feature;use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;class CanViewRandomNumberTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */
    public function testExample()
    {
        $response = $this->get('/random');        $response->assertStatus(200);        // laravel http-tests available-assertions don't include
        // numeric tests - let's roll our own
        // first grab the page content
        $content = $response->getContent();        // create a PHPUnit assertion on both >= and <=
        $this->assertThat(
            $content,
            $this->logicalAnd(
                $this->greaterThanOrEqual(0),
                $this->lessThanOrEqual(100)
            )
        );
    }
}

Sometimes a simple assertSeeText() is sufficient, but sometimes you need more flexibility. Even though Laravel is missing http-test regex assertions out-of-the-box, they are really easy to add when needed.

Testing may seem difficult, confusing, and time consuming, but I find that testing speeds up my process in the long run. And I have much more confidence in my work when I have tests to prove that it works as intended. Finally, I get the benefit of a nice regression suite that grows with the code.

An upside down red lightbulb on the left, frowning that says

Image via Gabriele Lana

Happy testing with regex patterns!

Download the code here.

You might also like