内容简介:测试 Laravel 应用的时候,你可能还想要“ 模拟 ”应用的特定状态,以便在测试中不让它们真的执行。例如,测试触发事件的控制器时,你可能想要模拟事件监听器以便它们不在测试期间真的执行。这样的话你就可以只测试控制器的 HTTP 响应,而不必担心事件监听器的执行,因为事件监听器可以在它们自己的测试用例中被测试。Laravel 开箱为模拟事件、任务以及门面提供了辅助函数,这些辅助函数主要是在 Mockery 之上提供了一个方便的层这样你就不必手动调用复杂的 Mockery 方法。当然,你也可以使用作为模拟的
简介
测试 Laravel 应用的时候,你可能还想要“ 模拟 ”应用的特定状态,以便在测试中不让它们真的执行。例如,测试触发事件的控制器时,你可能想要模拟事件监听器以便它们不在测试期间真的执行。这样的话你就可以只测试控制器的 HTTP 响应,而不必担心事件监听器的执行,因为事件监听器可以在它们自己的测试用例中被测试。
Laravel 开箱为模拟事件、任务以及门面提供了辅助函数,这些辅助函数主要是在 Mockery 之上提供了一个方便的层这样你就不必手动调用复杂的 Mockery 方法。当然,你也可以使用 Mockery 或 PHPUnit 来创建自己的模拟。
伪造 Bus
作为模拟的替代方案,你可以使用 Bus
门面的 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(); // Perform order shipping... Bus::assertDispatched(ShipOrder::class, function ($job) use ($order) { return $job->order->id === $order->id; }); // Assert a job was not dispatched... Bus::assertNotDispatched(AnotherJob::class); } }
伪造事件
作为模拟的替代方案,你可以使用 Event
门面的 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 { /** * Test order shipping. */ public function testOrderShipping() { Event::fake(); // Perform order shipping... Event::assertDispatched(OrderShipped::class, function ($e) use ($order) { return $e->order->id === $order->id; }); // Assert an event was dispatched twice... Event::assertDispatched(OrderShipped::class, 2); // Assert an event was not dispatched... Event::assertNotDispatched(OrderFailedToShip::class); } }
注:调用 Event:fake()
后,事件监听器不会执行,因此,如果你的测试使用了依赖于事件的模型工厂,例如在模型 creating
事件中创建一个 UUID,那么你需要在使用工厂后再调用 Event::fake()
。
有作用域的事件伪造
如果你只想为部分测试伪造事件监听器,可以使用 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 { /** * Test order process. */ public function testOrderProcess() { $order = Event::fakeFor(function () { $order = factory(Order::class)->create(); Event::assertDispatched(OrderCreated::class); return $order; }); // Events are dispatched as normal and observers will run ... $order->update([...]); } }
伪造邮件
你可以使用 Mail
门面的 fake
方法阻止邮件发送,然后断言发送给用户的可邮寄类,甚至检查接收的数据。使用 fake
的时候,断言会在测试代码执行后进行:
<?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(); // Perform order shipping... Mail::assertSent(OrderShipped::class, function ($mail) use ($order) { return $mail->order->id === $order->id; }); // Assert a message was sent to the given users... Mail::assertSent(OrderShipped::class, function ($mail) use ($user) { return $mail->hasTo($user->email) && $mail->hasCc('...') && $mail->hasBcc('...'); }); // Assert a mailable was sent twice... Mail::assertSent(OrderShipped::class, 2); // Assert a mailable was not sent... Mail::assertNotSent(AnotherMailable::class); } }
如果你将邮件发送推送到了后台异步队列,需要使用 assertQueued
来替代 assertSent
:
Mail::assertQueued(...); Mail::assertNotQueued(...);
伪造通知
你可以使用 Notification
门面的 fake
方法来阻止通知被发送,之后断言通知是否被发送给用户,甚至可以检查接收的数据。使用 fake
的时候,断言会在测试代码执行后进行:
<?php namespace Tests\Feature; use Tests\TestCase; use App\Notifications\OrderShipped; use Illuminate\Support\Facades\Notification; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\WithoutMiddleware; class ExampleTest extends TestCase { public function testOrderShipping() { Notification::fake(); // Perform order shipping... Notification::assertSentTo( $user, OrderShipped::class, function ($notification, $channels) use ($order) { return $notification->order->id === $order->id; } ); // Assert a notification was sent to the given users... Notification::assertSentTo( [$user], OrderShipped::class ); // Assert a notification was not sent... Notification::assertNotSentTo( [$user], AnotherNotification::class ); } }
伪造队列
作为模拟的替代方案,你可以使用 Queue
门面的 fake
方法来阻止任务被推动到队列,然后断言任务是否被推送到队列,甚至检查接收的数据。使用 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(); // Perform order shipping... Queue::assertPushed(ShipOrder::class, function ($job) use ($order) { return $job->order->id === $order->id; }); // Assert a job was pushed to a given queue... Queue::assertPushedOn('queue-name', ShipOrder::class); // Assert a job was pushed twice... Queue::assertPushed(ShipOrder::class, 2); // Assert a job was not pushed... Queue::assertNotPushed(AnotherJob::class); } }
伪造存储
Storage
门面的 fake
方法允许你轻松构造伪造硬盘,以及使用 UploadedFile
类生成的文件,从而极大简化了文件上传测试,例如:
<?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') ]); // Assert the file was stored... Storage::disk('avatars')->assertExists('avatar.jpg'); // Assert a file does not exist... Storage::disk('avatars')->assertMissing('missing.jpg'); } }
注:默认情况下, fake
方法会删除临时目录下的所有文件,如果你想要保留这些文件,可以使用 persistentFake
方法。
门面
不同于传统的静态方法调用,门面可以被模拟。这与传统静态方法相比是一个巨大的优势,并且你可以对依赖注入进行测试。测试的时候,你可能经常想要在控制器中模拟 Laravel 门面的调用,例如,看看下面的控制器动作:
<?php namespace App\Http\Controllers; use Illuminate\Support\Facades\Cache; class UserController extends Controller { /** * 显示应用用户列表 * * @return Response */ public function index() { $value = Cache::get('key'); // } }
我们可以通过使用 shouldReceive
方法模拟 Cache
门面的调用,该方法返回一个 Mockery
模拟的实例,由于门面通过 Laravel服务容器进行解析和管理,所以它们比通常的静态类更具有可测试性。例如,我们可以来模拟 Cache
门面 get
方法的调用:
<?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'); // ... } }
注:不要模拟 Request
门面,取而代之地,可以在测试时传递期望输入到 HTTP 辅助函数如 get
和 post
,类似地,也不要模拟 Config
门面,在测试中调用 Config::set
方法即可。
以上所述就是小编给大家介绍的《[ Laravel 5.7 文档 ] 测试系列 —— 模拟》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- [ Laravel 5.7 文档 ] 测试系列 —— HTTP 测试
- [ Laravel 5.7 文档 ] 测试系列 —— 数据库测试
- [ Laravel 5.7 文档 ] 测试系列 —— 控制台测试
- [ Laravel 5.7 文档 ] 测试 —— 快速入门
- [ Laravel 5.7 文档 ] 测试系列 —— 浏览器测试(Laravel Dusk)
- Springboot系列(七) 集成接口文档swagger,使用,测试
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。