php mocking,测试模拟器 Mocking

测试模拟器

简介

在 Laravel 应用程序测试中,你可能希望「模拟」应用程序的某些功能的行为,从而避免该部分在测试中真正执行。例如:在控制器执行过程中会触发事件(Event),从而避免该事件在测试控制器时真正执行。这允许你在仅测试控制器 HTTP 响应的情况时,而不必担心触发事件。当然,你也可以在单独的测试中测试该事件逻辑。

Laravel 针对事件、任务和 Facades 的模拟,提供了开箱即用的辅助函数。这些函数基于 Mocker 封装而成,使用非常方便,无需手动调用复杂的 Mockery 函数。当然你也可以使用 Mockery 或者使用 PHPUnit 创建自己的模拟器。

模拟对象

当模拟一个对象将通过 Laravel 的服务容器注入到应用中时,你将需要将模拟实例作为 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([...]);

}

}

邮件模拟

你可以是用 Mail Facade 的 fake 方法来模拟邮件发送,测试时不会真的发送邮件,然后你可以断言 mailables 发送给了用户,甚至可以检查他们收到的内容。使用 fakes 时,断言一般放在测试代码的后面:<?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);

}

}

如果你用后台任务执行邮件发送队列,你应该是用 assertQueued 代替 assertSent :Mail::assertQueued(...);

Mail::assertNotQueued(...);

通知模拟

你可以使用 Notification Facade 的 fake 方法来模拟通知的发送,测试时并不会真的发出通知。然后你可以断言 notifications 发送给了用户,甚至可以检查他们收到的内容。使用 fakes 时,断言一般放在测试代码后面:<?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

);

}

}

队列模拟

作为模拟替代方案,你可以使用 Queue Facade 的 fake 方法避免把任务真的放到队列中执行。然后你就可以断言任务已经被推送入队列了,甚至可以检查它们收到的数据。使用 fakes 时,断言一般放在测试代码的后面:<?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

]);

}

}

存储模拟

你可以使用 Storage Facade 的 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')

]);

// 断言文件已存储...

Storage::disk('avatars')->assertExists('avatar.jpg');

// 断言文件不存在...

Storage::disk('avatars')->assertMissing('missing.jpg');

}

}{tip}  默认情况下,fake 方法将删除临时目录下所有文件。如果你想保留这些文件,你可以使用 「persistentFake」。

Facades

与传统静态方法调用不同的是, facades 也可以被模拟。相较传统的静态方法而言,它具有很大的优势,即便你使用依赖注入,可测试性不逊半分。在测试中,你可能想在控制器中模拟对 Laravel Facade 的调用。比如下面控制器中的行为:<?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 Facade,此函数会返回一个 Mockery 实例。由于 Facade 的调用实际是由 Laravel 的 服务容器 管理的,所以 Facade 能比传统的静态类表现出更好的可测试性。下面,让我们模拟一下 Cache Facade 的 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');

// ...

}

}{note} 你不能模拟 Request Facade 。相反,在运行测试时如果需要传入指定参数,请使用 HTTP 辅助函数,比如 get 和 post 。同理,请在测试时通过调用 Config::set 来模拟 Config Facade。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
网站测试必不可少的! APMServ文件采用7-Zip压缩,比用WinRAR压缩减少了10M体积,请运行APMServ5.2.6_zip.exe 自解压包,将APMServ解压缩到一个路径中不含有汉字和空格的分区或目录即可。 ------------------------------------------------------------------------------------ APMServ 5.2.6 是一款拥有图形界面的快速搭建Apache 2.2.9、PHP 5.2.6、MySQL 5.1.28 &4.0.26、Nginx 0.7.19、Memcached 1.2.4、phpMyAdmin 2.11.9.2、OpenSSL、SQLite、 ZendOptimizer,以及ASP、CGI、Perl网站服务器平台的绿色软件。无需安装,具有灵活的移动 性,将其拷贝到其它目录、分区或别的电脑时,均只需点击APMServ.exe中的启动按钮,即可自 动进行相关设置,将Apache和MySQL安装为系统服务并启动。APMServ集合了Apache稳定安全的 优点,并拥有跟IIS一样便捷的图形管理界面,同时支持MySQL 5.0 & 4.0两个版本,虚拟主机、 虚拟目录、端口更改、SMTP、上传大小限制、自动全局变量、SSL证书制作、缓存性能优化等设 置,只需鼠标一点即可完成。 1、注意事项:APMServ程序所在路径不能含有汉字和空格。 2、MySQL默认用户名:root,密码为空 3、MySQL数据库文件存放目录:MySQL5.1\data或MySQL4.0\data 4、网站根目录[HTML,PHP]www\htdocs [ASP]www\asp [CGI,Perl]www\cgi-bin 5、访问本机请用http://127.0.0.1/或https://127.0.0.1/ (如果开启SSL) 6、非默认端口,网址为http://127.0.0.1:端口/或https://127.0.0.1:端口/ 7、如果在“扩展功能”中选择使用Memcached,它的端口为:11211 8、APMServ集成了以下软件: Apache 2.2.9 [HTTP服务器] Nginx 0.7.19 [HTTP服务器] NetBox 2.8 Build 4128 [HTTP服务器+ASP脚本解释引擎] PHP 5.2.6 [PHP脚本解释引擎] MiniPerl 5.8 [Perl脚本解释器] Memcached 1.2.4 [key-value内存缓存系统] MySQL 5.1.28 [MySQL数据库服务器] MySQL 4.0.26 [MySQL数据库服务器] phpMyAdmin 2.11.9.2 [MySQL数据库在线管理工具] eAccelerator 0.9.5.3 [PHP脚本加速引擎] ZendOptimizer 3.3.3 [PHP脚本加速引擎] OpenSSL 0.9.8h [HTTPS(SSL)安全传输协议]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值