Commonly Used Command Testing Functions
artisan()
- Signature:
artisan($command, $parameters = [])
- Explanation:This is probably the most important function in command testing! This function allows you to execute a command in the test code.
assertSuccessful()
- Signature:
assertSuccessful()
- Explanation:This function needs to be used after
$this->artisan()
, it can verify whether the command was successfully executed and returns an exit code0
(exit code0
generally means the program has completed without errors or exceptions).
assertFailed()
- Signature:
assertFailed()
- Explanation:This function needs to be followed by
$this->artisan()
, it can verify whether the command did not successfully complete, as long as the command does not respond with exit code0
, it will be treated asFailed
.
expectsConfirmation()
- Signature:
expectsConfirmation($question, $answer = 'no')
- Explanation:This function needs to be used after $this->artisan(), it can verify whether there is an expected confirmation message output.
expectsQuestion()
- Signature:
expectsQuestion($question, $answer)
- Explanation:This function needs to be followed by
$this->artisan()
, it can verify whether there is an expected prompt message output.
expectsOutput
- Signature:
expectsQuestion($output)
- Explanation:This function needs to be followed after
$this->artisan()
, it can verify if there is an expected message output in the text.
Examples
The above introduction about command-related testing functions, below is an example to show the practical application for everyone!
app/Console/Commands/DeleteUser.php
<?php
namespace App\Console\Commands;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
class DeleteUser extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'delete-user {userId}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Delete the user of given id';
/**
* Execute the console command.
*
* @return int
*/
public function handle(): int
{
$userId = $this->argument('userId');
$user = User::find($userId);
if (empty($user)) {
$this->warn('User not found!');
return 1;
}
if (!$this->confirm('Are you sure to delete this user?')) {
return 1;
}
$logOptions = ['Console output', 'Log file'];
$logType = $this->choice(
'Please select log option:',
$logOptions
);
$user->delete();
$message = 'User deleted';
if ($logType === $logOptions[0]) {
$this->info($message);
} else {
Log::info($message, ['userId' => $userId]);
}
return 0;
}
}
In the above code, we implemented a command DeleteUser
which is executed when we run php artisan delete-user {userId}
in the command line. This command has 1 input parameter userId
which is the ID of the user to be deleted. The functionality and behavior of this command are roughly as follows:
- Attempt to retrieve the User data with the given
userId
, if there is no data, display an error and end the command, otherwise continue the process. - Output the text
Are you sure you want to delete this user?
to let the user confirm whether to continue with the delete command, and decide whether to end the command prematurely or continue the process based on the user's response. - If the user decides to continue the process, ask the user how they want to record the operation.
- Delete the User data.
- Perform the record keeping based on the user’s chosen method.
- End the command and return an exit code
0
.
tests/Feature/CommandTest.php
<?php
namespace Tests\Feature;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class CommandTest extends TestCase
{
use RefreshDatabase;
public function testUserNotFound()
{
$this->artisan('delete-user',['userId' => 1])
->expectsOutput('User not found!')
->assertFailed();
}
public function testSuccessDeleteUser()
{
$user = User::factory()->create();
$userId = $user->id;
$this->artisan('delete-user', ['userId' => $userId])
->expectsConfirmation(
'Are you sure to delete this user?', 'yes'
)
->expectsQuestion('Please select log option:', 0)
->expectsOutput('User deleted')
->assertSuccessful();
$this->assertDatabaseCount('users', 0);
}
public function testCancelDeleteUser()
{
$user = User::factory()->create();
$userId = $user->id;
$this->artisan('delete-user', ['userId' => $userId])
->expectsConfirmation('Are you sure to delete this user?')
->assertSuccessful();
$this->assertDatabaseHas('users', [
'id' => $userId,
]);
}
}
The above test code consists of 3 test cases:
- The first test case,
testUserNotFound()
, tests the behavior and output of the command when the givenuserId
cannot be found in the database. - The second test case,
testSuccessDeleteUser()
, tests the behavior and output of the command when the givenuserId
can be found in the database and the user inputs "yes" to the confirmation prompt. - The third test case,
testCancelDeleteUser()
, tests the behavior and output of the command when the givenuserId
can be found in the database and the user inputs "no" to the confirmation prompt.
The above is an introduction to command testing, and I hope it is helpful to all readers.
Next, let’s talk about testing “failures”!
If you liked this article or found it helpful, feel free to give it some claps and follow the author!