DEV Community

Nasrul Hazim Bin Mohamad
Nasrul Hazim Bin Mohamad

Posted on • Updated on

Create Unit Test from Routes

You may previously skipped creating unit tests in your application, but you feels it's necessary for your application to have unit test to prevent more technical debts.

But...you have ton of routes, screens to test. Where to start?

I suggest write prepare all possible unit tests for all of your application routes.

This post cover how to automatically create unit tests based on route list of your application.

TLDR;

Create an artisan command,

php artisan make:command RouteTestCommand
Enter fullscreen mode Exit fullscreen mode

And update the class as following:

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Symfony\Component\Console\Output\BufferedOutput;

class RouteTestCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'route:test';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Generate tests from routes';

    protected BufferedOutput $buffer;

    /**
     * Execute the console command.
     */
    public function handle(): int
    {
        $this->buffer = new BufferedOutput();
        $this->callBuffer('route:list', [
            '--json' => true,
            '--except-vendor' => true,
        ]);

        $routes = json_decode($this->buffer->fetch(), JSON_OBJECT_AS_ARRAY);

        if (count($routes) == 0) {
            return $this->components->error("Your application doesn't have any routes.");
        }

        $this->info(count($routes).' routes found');

        foreach ($routes as $route) {
            if(empty(trim($route['uri'], '/'))) {
                $this->warn('Empty URI. Skip generate unit test for '.'('.$route['method'].') '.$route['uri']);

                continue;
            }

            $class = str(empty($route['name']) ? $route['uri'] : $route['name'])
                ->replace('.', ' ')
                ->headline()
                ->replace(' ', '').'Test';

            $this->info('Generating unit test for '.'('.$route['method'].') '.$route['uri']. ' - ' . $class);

            $this->call('pest:test', [
                'name' => $class,
                '--force' => true,
            ]);
        }

        return 0;
    }

    /**
     * Call another console command.
     *
     * @param  \Symfony\Component\Console\Command\Command|string  $command
     */
    public function callBuffer($command, array $arguments = []): int
    {
        return $this->runCommand($command, $arguments, $this->buffer);
    }
}

Enter fullscreen mode Exit fullscreen mode

Now, you can simply run:

php artisan route:test
Enter fullscreen mode Exit fullscreen mode

This will simply create all possible tests based on your routes.

Now you have a baseline where to start writing unit tests.

Do take note, I'm using PestPHP.

So, what's next?

It is possible to create classes based on models, APIs integrations, Livewire. But you need to understand how those classes populate and how we can generate the tests.

As for now, I just write based on routes, generate the unit tests.

Top comments (0)