I have a job that logs auth users page visit once per day and at the end there is a exception check. The problem comes in to get th unit test to prove the exception check should work.... and its not... -.-
job class
<?php
namespace App\Jobs\Auth;
use App\Models\Admin\VisitedPage;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Database\QueryException;
use Illuminate\Foundation\Queue\Queueable;
class SavePageVisit implements ShouldQueue
{
use Queueable;
public array $data = [];
/**
* Create a new job instance.
*/
public function __construct(array $data)
{
$this->queue = config('custom.queue.default');
$this->data = $data;
}
public function handle(): void
{
if (!$this->shouldProcessVisit()) {
return;
}
$this->createVisitRecord();
}
/**
* Determine if the visit should be processed.
*/
private function shouldProcessVisit(): bool
{
if (!$this->data['authUserId']) {
return false;
}
return !$this->hasVisitedToday();
}
/**
* Check if user has visited today.
*/
private function hasVisitedToday(): bool
{
return VisitedPage::where('user_id', $this->data['authUserId'])
->where('page_key', $this->data['pageKey'])
->whereDate('visited_at', now()->format('Y-m-d'))
->exists();
}
/**
* Create the visit record.
*/
public function createVisitRecord(): void
{
try {
VisitedPage::create($this->buildVisitData());
} catch (\Exception $exception) {
logger()->error('Failed to create visited page entry', [
'data' => $this->data,
'error' => $exception->getMessage(),
'exception' => get_class($exception)
]);
}
}
/**
* Build the visit data array.
*/
private function buildVisitData(): array
{
return [
'user_id' => $this->data['authUserId'],
'url' => $this->data['fullUrl'],
'from_url' => $this->data['backUrl'],
'page_key' => $this->data['pageKey'],
'pageable_id' => $this->data['pageAbleId'],
'pageable_type' => $this->data['pageableType'],
'visited_at' => now(),
];
}
}
unit test
it('logs database errors when visit record creation fails', function () {
// Arrange
$testData = [
'authUserId' => 1,
'fullUrl' => 'http://example.com',
'backUrl' => 'http://example.com/back',
'pageKey' => 'test_page',
'pageAbleId' => 1,
'pageableType' => 'TestType',
];
// Create a spy for the logger instead of strict mock
Log::spy();
// Mock the VisitedPage model to throw an exception
$mock = mock(VisitedPage::class);
$mock->shouldReceive('create')
->once()
->andThrow(new Exception('Database error'));
$this->app->instance(VisitedPage::class, $mock);
// Act
$job = new SavePageVisit($testData);
$job->createVisitRecord();
// Assert
Log::shouldHaveReceived('error')
->once()
->withArgs(function ($message, $context) use ($testData) {
return $message === 'Failed to create visited page entry' &&
$context['data'] === $testData &&
isset($context['error']) &&
isset($context['exception']);
});
});
error message
Mockery\Exception\InvalidCountException: Method error(<Any Arguments>) from Mockery_1_Illuminate_Log_LogManager should be called
at least 1 times but called 0 times