Mockery عمیق در Laravel — mock، spy، partial و expectation پیشرفته
Laravel facade را با Facade::fake() راحت mock میکنید؛ برای کلاس خودتان Mockery استاندارد PHP است. سطح مقدماتی در Unit test mock بود — اینجا expectation دقیق و mockهای شکننده را درست میکنیم.
ساخت mock و expectation
$gateway = Mockery::mock(PaymentGateway::class);
$gateway->shouldReceive('charge')
->once()
->with(10000, 'order-1')
->andReturn(['ref' => 'abc']);
$result = $gateway->charge(10000, 'order-1');
Argument matcher
->with(Mockery::type('int'), Mockery::pattern('/^order-/'))
->with(Mockery::on(fn ($order) => $order->id > 0))
->withArgs(function ($amount, $id) { return $amount > 0; })
وقتی مقدار دقیق مهم نیست — object پیچیده.
ترتیب و تعداد
->once() | ->twice() | ->times(3) | ->never()
->ordered() // ترتیب فراخوانی
->andReturn(1, 2, 3) // sequential
Exception از mock
->andThrow(new PaymentFailedException('declined'));
Spy — فراخوانی واقعی + assert
$spy = Mockery::spy(LogService::class);
$spy->shouldHaveReceived('info')->once()->with('order placed');
برای verify side effect بدون جایگزینی کامل.
Partial mock
$service = Mockery::mock(PostService::class)->makePartial();
$service->shouldReceive('sendNotification')->once();
$service->publish($post); // بقیه متدها واقعی
فقط یک متد fake — بقیه integration. با احتیاط — coupling.
mock در constructor Laravel
$this->instance(PostRepositoryInterface::class, $mock);
$action = app(CreatePostAction::class);
container swap — تست Action.
Mockery::close()
Pest/PHPUnit معمولاً در tearDown صدا میزند. اگر expectation برآورده نشود test fail — «leaked mock».
anti-patterns
- mock کردن class تحت تست
- shouldReceive روی همه متدها بدون دلیل
- assert روی ترتیب داخلی private
- overload mock برای static — fragile
جایگزین: fake Laravel
Mail::fake()، Http::fake() — نگهداری شده تیم. Test doubles.
جمعبندی
Mockery برای boundary interface — نه هر کلاس. Dataset: Pest dataset. Coverage: CI.