[ Laravel 5.7 文档 ] 测试系列 —— 模拟

栏目: PHP · 发布时间: 5年前

内容简介:测试 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 辅助函数如 getpost ,类似地,也不要模拟 Config 门面,在测试中调用 Config::set 方法即可。


以上所述就是小编给大家介绍的《[ Laravel 5.7 文档 ] 测试系列 —— 模拟》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Speed Up Your Site

Speed Up Your Site

Andrew B. King / New Riders Press / 2003-01-14 / USD 39.99

There's a time bomb on the web: user patience. It starts ticking each time someone opens one of your pages. You only have a few seconds to get compelling content onto the screen. Fail, and you can kis......一起来看看 《Speed Up Your Site》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

html转js在线工具
html转js在线工具

html转js在线工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换