Testsimulator Mocking
- Einführung
- Simulationsobjekt
- Aufgabensimulation
- Ereignissimulation
- E-Mail-Simulation
- Benachrichtigungssimulation
- Warteschlangensimulation
- Speicherung Simulation
- Fassaden
Einführung
Beim Testen einer Laravel-Anwendung möchten Sie möglicherweise das Verhalten bestimmter Funktionen Ihrer Anwendung „simulieren“ und so verhindern, dass dieser Teil tatsächlich im Test ausgeführt wird. Beispiel: Während der Ausführung des Controllers wird ein Ereignis (Event) ausgelöst, wodurch verhindert wird, dass das Ereignis beim Testen des Controllers tatsächlich ausgeführt wird. Dadurch können Sie nur die HTTP-Antwort des Controllers testen, ohne sich Gedanken über das Auslösen von Ereignissen machen zu müssen. Natürlich können Sie diese Ereignislogik auch in einem separaten Test testen.
Laravel bietet sofort einsatzbereite Hilfsfunktionen für die Simulation von Ereignissen, Aufgaben und Fassaden. Diese Funktionen basieren auf Mocker und sind sehr bequem zu verwenden. Es ist nicht erforderlich, komplexe Mockery-Funktionen manuell aufzurufen. Natürlich können Sie auch Mockery oder PHPUnit verwenden, um Ihren eigenen Emulator zu erstellen.
Mock Object
Wenn Sie ein Objekt verspotten, das über den Service-Container von Laravel in Ihre Anwendung eingefügt wird, werden Sie dies tun Die Scheininstanz muss als instance
in den Container eingebunden werden. Dadurch wird der Container angewiesen, eine Scheininstanz des Objekts zu verwenden, anstatt das reale Objekt zu erstellen:
use Mockery; use App\Service; $this->instance(Service::class, Mockery::mock(Service::class, function ($mock) { $mock->shouldReceive('process')->once(); }) );
Um den obigen Prozess komfortabler zu gestalten, können Sie die bereitgestellte grundlegende Testfallklasse von Laravel verwenden mock
Methode:
use App\Service;$this->mock(Service::class, function ($mock) { $mock->shouldReceive('process')->once(); });
Aufgabensimulation
Alternativ zur Simulation können Sie die Bus
Fassaden< verwenden 🎜> Methode, um zu verhindern, dass Aufgaben tatsächlich zur Ausführung verteilt werden. Bei Verwendung von Fake erscheinen im Allgemeinen Behauptungen hinter dem Testcode: fake
<?php namespace Tests\Feature; use Tests\TestCase;use App\Jobs\ShipOrder; use Illuminate\Support\Facades\Bus; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\WithoutMiddleware; class ExampleTest extends TestCase{ public function testOrderShipping() { Bus::fake(); // 执行订单发货... Bus::assertDispatched(ShipOrder::class, function ($job) use ($order) { return $job->order->id === $order->id; }); // 断言任务并未分发... Bus::assertNotDispatched(AnotherJob::class); } }Ereignissimulationals Mock Als an Alternativ können Sie die
Fassade des Event
nutzen Methode zum Simulieren des Ereignis-Listeners. Der Ereignis-Listener wird während des Tests nicht tatsächlich ausgelöst. Anschließend können Sie die laufenden Assertion-Ereignisse testen und sogar die empfangenen Daten überprüfen. Bei Verwendung von Fake erscheinen im Allgemeinen Behauptungen hinter dem Testcode: fake
<?php namespace Tests\Feature; use Tests\TestCase;use App\Events\OrderShipped; use App\Events\OrderFailedToShip; use Illuminate\Support\Facades\Event; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\WithoutMiddleware; class ExampleTest extends TestCase{ /** * 测试订单发送 */ public function testOrderShipping() { Event::fake(); // 执行订单发送... Event::assertDispatched(OrderShipped::class, function ($e) use ($order) { return $e->order->id === $order->id; }); // 断言一个事件被发送了两次... Event::assertDispatched(OrderShipped::class, 2); // 未分配断言事件... Event::assertNotDispatched(OrderFailedToShip::class); } }
{note} Die Ereignisüberwachung wird nach dem Aufruf vonSimulieren einer Teilmenge von Ereignissennicht ausgeführt. Daher müssen Ihre ereignisbasierten Tests das Fabrikmodell verwenden. Um beispielsweise eine UUID im
Event::fake()
-Ereignis des Modells zu erstellen, sollten Siecreating
nachEvent::fake()
aufrufen, um das Fabrikmodell zu verwenden.
Wenn Sie Ereignis-Listener nur für eine bestimmte Menge von Ereignissen simulieren möchten, können Sie diese an
oder übergeben fake
Methoden: fakeFor
/** * 测试订单流程 */ public function testOrderProcess(){ Event::fake([ OrderCreated::class, ]); $order = factory(Order::class)->create(); Event::assertDispatched(OrderCreated::class); // 其他事件照常发送... $order->update([...]); }Scoped Event Simulation Wenn Sie Event Listening nur für einen Teil des Tests simulieren möchten, Sie können
verwenden Methode: fakeFor
<?php namespace Tests\Feature; use App\Order;use Tests\TestCase; use App\Events\OrderCreated; use Illuminate\Support\Facades\Event; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\WithoutMiddleware; class ExampleTest extends TestCase{ /** * 测试订单流程 */ public function testOrderProcess() { $order = Event::fakeFor(function () { $order = factory(Order::class)->create(); Event::assertDispatched(OrderCreated::class); return $order; }); // 事件按正常方式发送,观察者将运行... $order->update([...]); } }
E-Mail-Simulation
Sie können die Mail
-Methode von fake
Facade verwenden, um den E-Mail-Versand während des Tests zu simulieren. Dann können Sie behaupten, dass die Mailings an gesendet werden Benutzer, oder überprüfen Sie sogar, was sie erhalten haben. Bei der Verwendung von Fakes werden Assertions im Allgemeinen nach dem Testcode platziert:
<?php namespace Tests\Feature; use Tests\TestCase;use App\Mail\OrderShipped; use Illuminate\Support\Facades\Mail; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\WithoutMiddleware; class ExampleTest extends TestCase{ public function testOrderShipping() { Mail::fake(); // 断言没有发送任何邮件... Mail::assertNothingSent(); // 执行订单发送... Mail::assertSent(OrderShipped::class, function ($mail) use ($order) { return $mail->order->id === $order->id; }); // 断言一条发送给用户的消息... Mail::assertSent(OrderShipped::class, function ($mail) use ($user) { return $mail->hasTo($user->email) && $mail->hasCc('...') && $mail->hasBcc('...'); }); // 断言邮件被发送两次... Mail::assertSent(OrderShipped::class, 2); // 断言没有发送邮件... Mail::assertNotSent(AnotherMailable::class); } }
Wenn Sie eine Hintergrundaufgabe zum Ausführen der E-Mail-Versandwarteschlange verwenden, sollten Sie assertQueued
anstelle von assertSent
verwenden :
Mail::assertQueued(...); Mail::assertNotQueued(...);
Benachrichtigungssimulation
Sie können die Notification
-Methode von Facade verwenden, um Benachrichtigungen zu simulieren , wird während des Tests tatsächlich keine Benachrichtigung gesendet. Sie können dann behaupten, dass Benachrichtigungen an den Benutzer gesendet wurden, und sogar überprüfen, was er erhalten hat. Bei der Verwendung von Fakes werden Assertions im Allgemeinen nach dem Testcode platziert: fake
<?php namespace Tests\Feature; use Tests\TestCase; use App\Notifications\OrderShipped; use Illuminate\Support\Facades\Notification; use Illuminate\Notifications\AnonymousNotifiable; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\WithoutMiddleware; class ExampleTest extends TestCase{ public function testOrderShipping() { Notification::fake(); // 断言没有发送通知... Notification::assertNothingSent(); // 执行订单发送... Notification::assertSentTo( $user, OrderShipped::class, function ($notification, $channels) use ($order) { return $notification->order->id === $order->id; } ); // 断言向给定用户发送了通知... Notification::assertSentTo( [$user], OrderShipped::class ); // 断言没有发送通知... Notification::assertNotSentTo( [$user], AnotherNotification::class ); // 断言通过 Notification::route() 方法发送通知... Notification::assertSentTo( new AnonymousNotifiable, OrderShipped::class ); } }WarteschlangensimulationAls Simulationsalternative , Sie können die
-Methode von Queue
Facade verwenden, um zu vermeiden, dass die Aufgabe tatsächlich zur Ausführung in die Warteschlange gestellt wird. Sie können dann bestätigen, dass Aufgaben in die Warteschlange verschoben wurden, und sogar die empfangenen Daten überprüfen. Bei der Verwendung von Fakes werden Behauptungen im Allgemeinen nach dem Testcode platziert: fake
<?php namespace Tests\Feature; use Tests\TestCase;use App\Jobs\ShipOrder; use Illuminate\Support\Facades\Queue; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\WithoutMiddleware; class ExampleTest extends TestCase{ public function testOrderShipping() { Queue::fake(); // 断言没有任务被发送... Queue::assertNothingPushed(); // 执行订单发送... Queue::assertPushed(ShipOrder::class, function ($job) use ($order) { return $job->order->id === $order->id; }); // 断言任务进入了指定队列... Queue::assertPushedOn('queue-name', ShipOrder::class); // 断言任务进入2次... Queue::assertPushed(ShipOrder::class, 2); // 断言没有一个任务进入队列... Queue::assertNotPushed(AnotherJob::class); // 断言任务是由特定的通道发送的... Queue::assertPushedWithChain(ShipOrder::class, [ AnotherJob::class, FinalJob::class ]); } }Store-SimulationSie können < verwenden 🎜> Die
-Methode von Facade kann in Kombination mit UploadedFile problemlos eine simulierte Festplatte generieren Das Tool zur Generierung von Klassendateien vereinfacht das Testen des Datei-Uploads erheblich. Beispiel: Storage
<?php namespace Tests\Feature; use Tests\TestCase; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Storage; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\WithoutMiddleware; class ExampleTest extends TestCase{ public function testAvatarUpload() { Storage::fake('avatars'); $response = $this->json('POST', '/avatar', [ 'avatar' => UploadedFile::fake()->image('avatar.jpg') ]); // 断言文件已存储... Storage::disk('avatars')->assertExists('avatar.jpg'); // 断言文件不存在... Storage::disk('avatars')->assertMissing('missing.jpg'); } }
fake
{tip} Standardmäßig löscht die Methode alle Dateien im temporären Verzeichnis. Wenn Sie diese Dateien behalten möchten, können Sie „persistentFake“ verwenden.
fake
Fassaden
Im Gegensatz zu herkömmlichen statischen Methodenaufrufen können auch Fassaden simuliert werden. Im Vergleich zu herkömmlichen statischen Methoden bietet es große Vorteile. Selbst wenn Sie die Abhängigkeitsinjektion verwenden, ist die Testbarkeit nicht um die Hälfte schlechter. In Ihren Tests möchten Sie möglicherweise Aufrufe an die Laravel-Fassade in Ihrem Controller simulieren. Zum Beispiel das Verhalten im folgenden Controller:
<?php namespace App\Http\Controllers; use Illuminate\Support\Facades\Cache; class UserController extends Controller{ /** * 显示应用里所有用户 * * @return Response */ public function index() { $value = Cache::get('key'); // } }
Wir können die shouldReceive
Facade durch die Cache
-Methode simulieren, die eine Mockery-Instanz zurückgibt. Da Facade-Aufrufe tatsächlich vom Service-Container von Laravel verwaltet werden, kann Facade eine bessere Testbarkeit aufweisen als herkömmliche statische Klassen. Als Nächstes verspotten wir die Cache
-Methode der get
Facade:
<?php namespace Tests\Feature; use Tests\TestCase; use Illuminate\Support\Facades\Cache; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\WithoutMiddleware; class UserControllerTest extends TestCase{ public function testGetIndex() { Cache::shouldReceive('get') ->once() ->with('key') ->andReturn('value'); $response = $this->get('/users'); // ... } }
{note} Sie können die
Request
Facade nicht verspotten. Verwenden Sie stattdessen HTTP-Hilfsfunktionen wieget
undpost
, wenn Sie beim Ausführen Ihrer Tests bestimmte Parameter übergeben müssen. Simulieren Sie in ähnlicher Weise bitte dieConfig::set
-Fassade, indem Sie während des TestsConfig
aufrufen.