تقلید
معرفی
هنگام آزمایش برنامه های لاراول، ممکن است بخواهید جنبه های خاصی از برنامه خود را "تقلید" کنید تا در طول یک آزمایش خاص اجرا نشوند. به عنوان مثال، هنگام آزمایش کنترلری که یک رویداد را ارسال می کند، ممکن است بخواهید شنوندگان رویداد را تقلید کنید تا در طول آزمایش واقعاً اجرا نشوند. این به شما امکان می دهد فقط پاسخ HTTP کنترلر را بدون نگرانی در مورد اجرای شنوندگان رویداد آزمایش کنید زیرا شنوندگان رویداد می توانند در مورد آزمایشی خودشان آزمایش شوند.
لاراول روش های مفیدی را برای تقلید وقایع، مشاغل و دیگر نماها از جعبه ارائه می دهد. این کمکها در درجه اول یک لایه راحتی روی Mockery ارائه میکنند، بنابراین شما مجبور نیستید به صورت دستی فراخوانیهای پیچیده روش Mockery را انجام دهید.
اشیاء تقلید
هنگام تقلید کردن یک شی که قرار است از طریق
کانتینر سرویس
لاراول به برنامه شما تزریق شود ، باید نمونه تقلید شده خود را به عنوان یک
instance
اتصال به کانتینر متصل کنید. این به کانتینر دستور می دهد که به جای ساختن خود شی، از نمونه تقلید شده شما از شی استفاده کند:
use App\Service;use Mockery;use Mockery\MockInterface; test('something can be mocked', function () { $this->instance( Service::class, Mockery::mock(Service::class, function (MockInterface $mock) { $mock->shouldReceive('process')->once(); }) );});
use App\Service;use Mockery;use Mockery\MockInterface; public function test_something_can_be_mocked(): void{ $this->instance( Service::class, Mockery::mock(Service::class, function (MockInterface $mock) { $mock->shouldReceive('process')->once(); }) );}
برای راحتتر کردن این کار، میتوانید از
mock
روشی استفاده کنید که توسط کلاس تست پایه لاراول ارائه شده است. به عنوان مثال، مثال زیر معادل مثال بالا است:
use App\Service;use Mockery\MockInterface; $mock = $this->mock(Service::class, function (MockInterface $mock) { $mock->shouldReceive('process')->once();});
ممکن است زمانی از این روش استفاده کنید
partialMock
که فقط نیاز به تقلید چند روش از یک شی دارید. متدهایی که تقلید نمی شوند در صورت فراخوانی به طور معمول اجرا می شوند:
use App\Service;use Mockery\MockInterface; $mock = $this->partialMock(Service::class, function (MockInterface $mock) { $mock->shouldReceive('process')->once();});
به طور مشابه، اگر میخواهید روی یک شی
جاسوسی کنید
، کلاس آزمایشی پایه لاراول
spy
روشی را به عنوان یک پوشش مناسب در اطراف
Mockery::spy
متد ارائه میکند. جاسوس ها شبیه به تقلید هستند. با این حال، جاسوسها هرگونه تعامل بین جاسوس و کد مورد آزمایش را ضبط میکنند و به شما امکان میدهند پس از اجرای کد، اظهارنظر کنید:
use App\Service; $spy = $this->spy(Service::class); // ... $spy->shouldHaveReceived('process');
نماهای تقلید
برخلاف فراخوانیهای روش استاتیک سنتی، نماها (از جمله نماهای بلادرنگ ) ممکن است مورد تقلید قرار گیرند. این مزیت بزرگی نسبت به روشهای استاتیک سنتی دارد و همان آزمایشپذیری را به شما میدهد که اگر از تزریق وابستگی سنتی استفاده میکردید، خواهید داشت. هنگام آزمایش، ممکن است اغلب بخواهید تماسی به نمای لاراول که در یکی از کنترلرهای شما رخ می دهد را تقلید کنید. به عنوان مثال، عمل کنترلر زیر را در نظر بگیرید:
<?php namespace App\Http\Controllers; use Illuminate\Support\Facades\Cache; class UserController extends Controller{ /** * Retrieve a list of all users of the application. */ public function index(): array { $value = Cache::get('key'); return [ // ... ]; }}
Cache
ما میتوانیم با استفاده از
shouldReceive
روشی که نمونهای از ماک
تقلید
را برمیگرداند ، تماس را به نما تقلید کنیم
. از آنجایی که نماها در واقع توسط
کانتینر سرویس
لاراول حل و فصل می شوند
، آزمایش پذیری بسیار بیشتری نسبت به یک کلاس استاتیک معمولی دارند. به عنوان مثال، بیایید فراخوانی خود را به روش
Cache
نما تقلید کنیم
get
:
<?php use Illuminate\Support\Facades\Cache; test('get index', function () { Cache::shouldReceive('get') ->once() ->with('key') ->andReturn('value'); $response = $this->get('/users'); // ...});
<?php namespace Tests\Feature; use Illuminate\Support\Facades\Cache;use Tests\TestCase; class UserControllerTest extends TestCase{ public function test_get_index(): void { Cache::shouldReceive('get') ->once() ->with('key') ->andReturn('value'); $response = $this->get('/users'); // ... }}
شما نباید
Request
نما را تقلید کنید. در عوض، ورودی مورد نظر خود را به روشهای تست HTTP مانندget
وpost
هنگام اجرای آزمایش ارسال کنید. به همین ترتیب، به جای تقلیدConfig
نما،Config::set
روش را در تست های خود فراخوانی کنید.
جاسوس های نما
اگر می خواهید روی یک نما
جاسوسی کنید
، می توانید
spy
روش را در نمای مربوطه فراخوانی کنید. جاسوس ها شبیه به تقلید هستند. با این حال، جاسوسها هرگونه تعامل بین جاسوس و کد مورد آزمایش را ضبط میکنند و به شما امکان میدهند پس از اجرای کد، اظهارنظر کنید:
<?php use Illuminate\Support\Facades\Cache; test('values are be stored in cache', function () { Cache::spy(); $response = $this->get('/'); $response->assertStatus(200); Cache::shouldHaveReceived('put')->once()->with('name', 'Taylor', 10);});
use Illuminate\Support\Facades\Cache; public function test_values_are_be_stored_in_cache(): void{ Cache::spy(); $response = $this->get('/'); $response->assertStatus(200); Cache::shouldHaveReceived('put')->once()->with('name', 'Taylor', 10);}
تعامل با زمان
هنگام آزمایش، ممکن است گهگاه نیاز به تغییر زمان برگشتی توسط کمککنندگانی مانند
now
یا داشته باشید
Illuminate\Support\Carbon::now()
. خوشبختانه، کلاس تست ویژگی پایه لاراول شامل کمک هایی است که به شما امکان می دهد زمان فعلی را دستکاری کنید:
test('time can be manipulated', function () { // Travel into the future... $this->travel(5)->milliseconds(); $this->travel(5)->seconds(); $this->travel(5)->minutes(); $this->travel(5)->hours(); $this->travel(5)->days(); $this->travel(5)->weeks(); $this->travel(5)->years(); // Travel into the past... $this->travel(-5)->hours(); // Travel to an explicit time... $this->travelTo(now()->subHours(6)); // Return back to the present time... $this->travelBack();});
public function test_time_can_be_manipulated(): void{ // Travel into the future... $this->travel(5)->milliseconds(); $this->travel(5)->seconds(); $this->travel(5)->minutes(); $this->travel(5)->hours(); $this->travel(5)->days(); $this->travel(5)->weeks(); $this->travel(5)->years(); // Travel into the past... $this->travel(-5)->hours(); // Travel to an explicit time... $this->travelTo(now()->subHours(6)); // Return back to the present time... $this->travelBack();}
همچنین میتوانید روشهای مختلف سفر در زمان را محدود کنید. بسته شدن با زمان ثابت در زمان مشخص شده فراخوانی می شود. هنگامی که بسته شدن اجرا شد، زمان به صورت عادی از سر گرفته می شود:
$this->travel(5)->days(function () { // Test something five days into the future...}); $this->travelTo(now()->subDays(10), function () { // Test something during a given moment...});
این
freezeTime
روش ممکن است برای ثابت کردن زمان فعلی استفاده شود. به طور مشابه، این
freezeSecond
روش زمان فعلی را متوقف می کند اما در شروع ثانیه فعلی:
use Illuminate\Support\Carbon; // Freeze time and resume normal time after executing closure...$this->freezeTime(function (Carbon $time) { // ...}); // Freeze time at the current second and resume normal time after executing closure...$this->freezeSecond(function (Carbon $time) { // ...})
همانطور که انتظار دارید، همه روشهایی که در بالا مورد بحث قرار گرفتند، در درجه اول برای آزمایش رفتار برنامه حساس به زمان، مانند قفل کردن پستهای غیرفعال در یک انجمن گفتگو مفید هستند:
use App\Models\Thread; test('forum threads lock after one week of inactivity', function () { $thread = Thread::factory()->create(); $this->travel(1)->week(); expect($thread->isLockedByInactivity())->toBeTrue();});
use App\Models\Thread; public function test_forum_threads_lock_after_one_week_of_inactivity(){ $thread = Thread::factory()->create(); $this->travel(1)->week(); $this->assertTrue($thread->isLockedByInactivity());}