Testing PHP: PHPUnit vs. Artisan Commands

Enhancing PHP Unit Tests: Adding Artisan Test Styles to PHPUnit Output

When working on a Laravel project, I often find myself toggling between phpunit for running unit tests and php artisan test for its enhanced output. The latter not only offers a more visually pleasing format but provides helpful additional information like the duration of each test. This is particularly useful for identifying slow tests in the suite — a crucial aspect when aiming for efficient test optimizations.

The standard output of PHPUnit, while thorough, lacks the immediate clarity and additional metrics provided by Laravel’s php artisan test. Knowing that this command is essentially a wrapper for PHPUnit with an enhanced console output sparked my curiosity: could I somehow combine the benefits of using php artisan test (specifically its appealing format and test duration data), with the flexibility and additional logging capabilities of running phpunit directly?

Exploring the Artisan Command

Laravel’s php artisan test leverages a package called Collision, which enhances the PHPUnit output. Collision provides a beautifully styled output, making test results more readable and easier to debug. My challenge was to bring some of this styling and functionality, such as test execution time, directly into the bare PHPUnit setting.

Customizing PHPUnit using Listeners

PHPUnit supports “listeners” which can be used to hook into the test execution lifecycle to add additional functionality or modify the output. By defining a custom listener, I might capture timing data for each test and output it in a format similar to what php artisan test provides.

Considering our Laravel setup, here’s a basic setup you could experiment with:

  1. Create a Custom Test Listener

I can start by creating a custom listener class within my Laravel project that implements PHPUnit\Framework\TestListener. This listener would listen for test start and test end events to calculate and store test durations.

// app/Testing/CustomTestListener.php
   namespace App\Testing;

   use PHPUnit\Framework\AssertionFailedError;
   use PHPUnit\Framework\Test;
   use PHPUnit\Framework\TestListener;
   use PHPUnit\Framework\TestSuite;
   use PHPUnit\Framework\Warning;

   class CustomTestListener implements TestListener {
       private $startTime;

       public function startTest(Test $test) : void {
           $this->startTime = microtime(true);
       }

       public function endTest(Test $test, float $time) : void {
           $duration = microtime(true) - $this->startTime;
           echo sprintf("%s took %s seconds\n", get_class($test), number_format($duration, 3));
       }

       // Other necessary methods would be implemented here, potentially no-ops or logging.
   }

  1. Register the Listener in phpunit.xml

Next, I would configure PHPUnit to use this listener by adding it to my phpunit.xml configuration file:

<listeners>
       <listener class="App\Testing\CustomTestListener" file="app/Testing/CustomTestListener.php"/>
   </listeners>

  1. Running PHPUnit with the Custom Listener

Now, when I run phpunit, it should utilize the custom listener, echoing out the duration of each test, emulating part of what php artisan test outputs.

While this setup doesn’t fully replicate the style of php artisan test, it does provide the useful time metrics, which was a key feature I didn’t want to miss from Laravel’s testing output.

By bridging some of the functionalities of php artisan test and phpunit in this way, I can maintain the necessary flexibility for logging and other configurations within PHPUnit testing, while gaining additional insights typically provided by Laravel’s enhanced test output. This blended approach allows me to enhance the readability and effectiveness of my testing workflow in Laravel projects.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *