Simulateur de test moqueur
~
Simulation d'événements
- Simulation d'événements cadrés
- Simulation d'e-mails
- Simulation de notifications
- Façades
Introduction
Dans les tests d'applications Laravel, vous souhaiterez peut-être "simuler" le comportement de certaines fonctionnalités de l'application, empêchant ainsi cette partie de s'exécuter réellement dans le test. Par exemple : un événement (Event) sera déclenché lors de l'exécution du contrôleur, empêchant ainsi l'exécution réelle de l'événement lors du test du contrôleur. Cela vous permet de tester uniquement la réponse HTTP du contrôleur sans avoir à vous soucier du déclenchement d'événements. Bien entendu, vous pouvez également tester cette logique d’événement dans un test séparé.
Laravel fournit des fonctions d'assistance prêtes à l'emploi pour la simulation d'événements, de tâches et de façades. Ces fonctions sont encapsulées sur la base de Mocker et sont très pratiques à utiliser. Il n'est pas nécessaire d'appeler manuellement des fonctions Mockery complexes. Bien sûr, vous pouvez également utiliser Mockery ou créer votre propre émulateur en utilisant PHPUnit.
Objets simulés
Lorsque vous vous moquez d'un objet qui sera injecté dans votre application via le conteneur de service de Laravel, vous devrez lier l'instance fictive au conteneur en tant que
instance
. Cela indiquera au conteneur d'utiliser une instance fictive de l'objet au lieu de construire l'objet réel :instance
绑定到容器中。这将告诉容器使用对象的模拟实例,而不是构造对象的真身:use Mockery; use App\Service; $this->instance(Service::class, Mockery::mock(Service::class, function ($mock) { $mock->shouldReceive('process')->once(); }) );
为了让以上过程更加便捷,你可以使用 Laravel 的基本测试用例类提供
mock
方法:use App\Service;$this->mock(Service::class, function ($mock) { $mock->shouldReceive('process')->once(); });
任务模拟
作为模拟的替代方式,你可以使用
Bus
Facade 的fake
方法来防止任务被真正分发执行。使用 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); } }
事件模拟
作为 mock 的替代方法,你可以使用
Event
Facade 的fake
方法来模拟事件监听,测试的时候并不会真正触发事件监听器。然后你就可以测试断言事件运行了,甚至可以检查他们接收的数据。使用 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} 调用
Event::fake()
后不会执行事件监听。所以,你基于事件的测试必须使用工厂模型,例如,在模型的creating
事件中创建 UUID ,你应该调用Event::fake()
之后 使用工厂模型。模拟事件的子集
如果你只想为特定的一组事件模拟事件监听器,你可以将它们传递给
fake
或fakeFor
方法:/** * 测试订单流程 */ public function testOrderProcess(){ Event::fake([ OrderCreated::class, ]); $order = factory(Order::class)->create(); Event::assertDispatched(OrderCreated::class); // 其他事件照常发送... $order->update([...]); }
Scoped 事件模拟
如果你只想为部分测试模拟事件监听,则可以使用
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([...]); } }
Pour rendre le processus ci-dessus plus pratique, vous pouvez utiliser la classe de cas de test de base de Laravel pour fournir lesimulateur
méthode :<?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); } }
Simulation de tâches🎜🎜Comme alternative à la simulation, vous pouvez utiliserBus
Méthodefake
de Facade pour empêcher les tâches d'être réellement distribuées pour exécution. Lors de l'utilisation de fake, des assertions apparaissent généralement derrière le code de test : 🎜Mail::assertQueued(...); Mail::assertNotQueued(...);
🎜🎜🎜🎜🎜Event simulation🎜🎜 En guise de Alternative à la simulation, vous pouvez utiliser la méthodeFake
de la façadeEvent
pour simuler les écouteurs d'événements. Les écouteurs d'événements ne seront pas réellement déclenchés pendant les tests. Vous pouvez ensuite tester les événements d'assertion en cours d'exécution et même inspecter les données qu'ils reçoivent. Lors de l'utilisation de fake, des assertions apparaissent généralement derrière le code de test : 🎜<?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 ); } }
🎜{note} La surveillance des événements ne sera pas exécutée après l'appel de
Event::fake()
. Par conséquent, vos tests basés sur les événements doivent utiliser un modèle d'usine. Par exemple, pour créer un UUID dans l'événementcreating
du modèle, vous devez appelerEvent::fake()
< strong> ensuite Utilisez le modèle d'usine. 🎜🎜Simuler un sous-ensemble d'événements
🎜Si vous souhaitez uniquement simuler un écouteur d'événements pour un ensemble spécifique d'événements, Ils peuvent être transmis aux méthodesfake
oufakeFor
: 🎜<?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 ]); } }
🎜🎜🎜🎜Simulation d'événements à portée
🎜Si vous souhaitez uniquement simuler l'écoute d'événements pendant une partie du test, vous pouvez utiliser la méthodefakeFor
: 🎜<?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'); } }
🎜🎜🎜🎜🎜🎜Mail simulation
Vous pouvez utiliser la méthode
fake
de la façadeMail
pour simuler l'envoi d'email. L'email ne sera pas réellement envoyé pendant le test, et vous pourrez alors affirmer. que les mailables sont envoyés aux utilisateurs peuvent même vérifier ce qu'ils ont reçu. Lors de l'utilisation de faux, les assertions sont généralement placées après le code de test :Mail
Facade 的fake
方法来模拟邮件发送,测试时不会真的发送邮件,然后你可以断言 mailables 发送给了用户,甚至可以检查他们收到的内容。使用 fakes 时,断言一般放在测试代码的后面:<?php namespace App\Http\Controllers; use Illuminate\Support\Facades\Cache; class UserController extends Controller{ /** * 显示应用里所有用户 * * @return Response */ public function index() { $value = Cache::get('key'); // } }
如果你用后台任务执行邮件发送队列,你应该是用
assertQueued
代替assertSent
:<?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'); // ... } }
通知模拟
你可以使用
rrreeeNotification
Facade 的fake
方法来模拟通知的发送,测试时并不会真的发出通知。然后你可以断言 notifications 发送给了用户,甚至可以检查他们收到的内容。使用 fakes 时,断言一般放在测试代码后面:队列模拟
作为模拟替代方案,你可以使用
rrreeeQueue
Facade 的fake
方法避免把任务真的放到队列中执行。然后你就可以断言任务已经被推送入队列了,甚至可以检查它们收到的数据。使用 fakes 时,断言一般放在测试代码的后面:存储模拟
你可以使用
rrreeeStorage
Facade 的fake
方法,轻松的生成一个模拟磁盘,结合 UploadedFile 类的文件生成工具,极大的简化了文件上传测试。例如:
rrreee{tip} 默认情况下,
Si vous utilisez une tâche en arrière-plan pour exécuter la file d'attente d'envoi d'e-mails, vous devez utiliserfake
rrreeeassertQueued
au lieu deassertSent
:Simulation de notification🎜Vous pouvez utiliser la façade deNotification
Méthodefake
pour simuler l'envoi de notifications. La notification ne sera pas réellement envoyée pendant le test. Vous pouvez alors affirmer que des notifications ont été envoyées à l'utilisateur et même inspecter ce qu'il a reçu. Lors de l'utilisation de faux, les assertions sont généralement placées derrière le code de test : 🎜rrreee🎜🎜🎜🎜🎜queue simulation🎜🎜 as simulation Alternativement, vous pouvez utiliser la méthodeFake
deQueue
Facade pour éviter de mettre la tâche dans la file d'attente pour exécution. Vous pouvez ensuite affirmer que les tâches ont été placées dans la file d'attente et même inspecter les données qu'elles ont reçues. Lors de l'utilisation de faux, les assertions sont généralement placées derrière le code de test : 🎜rrreee🎜🎜🎜🎜🎜storage simulation🎜🎜you Vous pouvez utiliser la méthode. 🎜🎜fake
de la façadeStorage
pour générer facilement un disque simulé. Combinée à l'outil de génération de fichiers de la classe UploadedFile, elle simplifie grandement les tests de téléchargement de fichiers. Par exemple : 🎜rrreee🎜{tip} Par défaut, la méthode
fake
supprimera tous les fichiers du répertoire temporaire. Si vous souhaitez conserver ces fichiers, vous pouvez utiliser "persistentFake". 🎜🎜🎜🎜🎜🎜🎜🎜Façades
Contrairement aux appels de méthodes statiques traditionnelles, les façades peuvent également être simulées. Par rapport aux méthodes statiques traditionnelles, elle présente de grands avantages. Même si vous utilisez l'injection de dépendances, la testabilité n'est pas inférieure de moitié. Dans vos tests, vous souhaiterez peut-être simuler des appels vers Laravel Facade dans votre contrôleur. Par exemple, le comportement du contrôleur ci-dessous :
rrreeeNous pouvons simuler la façade
rrreeeCache
via la méthodeshouldReceive
. Cette fonction renverra un Instance MockeryshouldReceive
方法来模拟Cache
Facade,此函数会返回一个 Mockery 实例。由于 Facade 的调用实际是由 Laravel 的 服务容器 管理的,所以 Facade 能比传统的静态类表现出更好的可测试性。下面,让我们模拟一下Cache
Facade 的get
方法:{note} 你不能模拟
rrreee{note} Vous ne pouvez pas simuler la façadeRequest
Facade 。相反,在运行测试时如果需要传入指定参数,请使用 HTTP 辅助函数,比如get
和post
。同理,请在测试时通过调用Config::set
来模拟Config
. Étant donné que les appels Facade sont en fait gérés par le conteneur de services de Laravel, Facade peut montrer une meilleure testabilité que les classes statiques traditionnelles. Ensuite, simulons la méthodeget
de la façadeCache
:Request
. Utilisez plutôt les fonctions d'assistance HTTP telles queget
etpost
si vous devez transmettre des paramètres spécifiques lors de l'exécution de vos tests. De même, veuillez simuler la façadeConfig
en appelantConfig::set
pendant les tests. LearnKu.com