Back to Course |
Testing in Laravel 11: Advanced Level

Testing Artisan Commands

I want to demonstrate how to test Artisan commands and their results, outputs, or errors.


The Artisan Command

Imagine you have an Artisan command called php artisan product:publish, which takes the product ID as a parameter.

It only publishes the product by setting the published_at to now(). But it also checks if the product is found and whether it's published already. In those cases, it throws errors.

How do we test and simulate that from our tests?

use App\Models\Product;
use Illuminate\Console\Command;
 
class ProductPublishCommand extends Command
{
protected $signature = 'product:publish {id : ID of the product to publish}';
 
protected $description = 'Publishes the product';
 
public function handle(): void
{
$product = Product::find($this->argument('id'));
 
if (!$product) {
$this->fail('Product not found');
}
 
if ($product->published_at) {
$this->fail('Product is already published');
}
 
$product->update(['published_at' => now()]);
$this->components->success('Product published');
}
}

The Tests

In the test, you can run an Artisan command using $this->artisan(). In a second parameter, you can pass parameters as an array.

So, first, let's test that the command runs successfully.

use App\Models\Product;
 
test('artisan publish command successful', function () {
$product = Product::factory()->create();
 
$this->artisan('product:publish', ['id' => $product->id])
->assertSuccessful();
});

Alternatively, you can use assertExitCode() with exit code number:

  • 0 - success
  • 1 - failed
test('artisan publish command successful', function () {
$product = Product::factory()->create();
 
$this->artisan('product:publish', ['id' => $product->id])
->assertExitCode(0);
});

Let's add a test where the output fails.

test('artisan publish command fails', function () {
$this->artisan('product:publish', ['id' => 1])
->assertFailed();
});

Also, you can check the output message. For example, in this command, Product not found or Product is already published.

test('artisan publish command fails', function () {
$this->artisan('product:publish', ['id' => 1])
->assertFailed()
->expectsOutputToContain('Product not found');
});

There are other expectation methods, like expectsChoice() or expectsConfirmation(). For more, check the official documentation.