I don't test what I don't own. I have no reason to test the schedule:* commands. I only test the "action" classes I have in the commands.
So if I have something like:
class SendEmails extends Command
{
protected $signature = 'mail:send {user}';
protected $description = 'Send a marketing email to a user';
public function handle(DripEmailer $drip)
{
$drip->send(User::query()->find($this->argument('user')));
}
}
I usually rewrite it as:
class SendEmails extends Command
{
protected $signature = 'mail:send {user}';
protected $description = 'Send a marketing email to a user';
public function handle(SendMarketingEmailToUser $action)
{
$action($this->argument('user')); // I usually create "action" classes as invokable so I have a hint when I open that class what is used for
}
}
class SendMarketingEmailToUser
{
public function __construct(public MyDripEmailer $drip) {}
public function __invoke(int $userId): void
{
$this->drip->send(User::query()->find($userId));
}
}
Then I write two tests. One to test my SendMarketingEmailToUser class and the second one to test that the SendEmails command is calling SendMarketingEmailToUser class where I mock SendMarketingEmailToUser class.
Also, I never call DripEmailer directly. I either encapsulate it in some service class, or I just extend it and use MyDripEmailer class instead. That way if I have to change something I have a nice place where to write additional logic.